reactjs 为什么typescript推断我的动态键是返回对象的函数

0md85ypi  于 2023-04-29  发布在  React
关注(0)|答案(2)|浏览(101)

const a = { something:return true,};
返回

<input
        type="checkbox"
        checked={
          a["Some Thing".toLowerCase().replace(/\s+/g, "") as keyof boolean]
        }
      />

我得到一个类型脚本错误Type '()=〉Object' is not assignable to type 'boolean|未定义'
试着用谷歌搜索,没能找到任何有这个特殊属性的东西。我能找到的唯一解决办法就是硬编码所有东西

voase2hg

voase2hg1#

keyof运算符接受一个类型并返回其键类型的并集。因此,keyof boolean类型将是您可以用于索引 * 到 * boolean类型的值的键类型。你肯定不是这个意思没有人会把boolean作为对象来索引。让我们看看keyof boolean是什么:

type KeyofBoolean = keyof boolean;
// type KeyofBoolean = "valueOf"

啊,有道理;编译器只知道the valueOf property of the autoboxed Boolean。如果你想写的话,你可以这样写:

const b = (true).valueOf(); // boolean

不是你想的那样。那么

"Some Thing".toLowerCase().replace(/\s+/g, "") as keyof boolean

就等于说

"Some Thing".toLowerCase().replace(/\s+/g, "") as "valueOf"

所以编译器认为你在写

a["valueOf"]

a.valueOf

which exists and it's a function that returns an object() => Object。编译器会抱怨inputchecked属性可能不应该是返回对象的函数。
哎呀。
所以keyof boolean本质上是一个错误或错别字;你大概是想说它是一个a的密钥,它的类型是typeof a(使用the typeof type query operator):

<input
  type="checkbox"
  checked={
    a["Some Thing".toLowerCase().replace(/\s+/g, "") as keyof typeof a]
  }
/> // okay

我不确定这个问题是否需要这样一个完整的答案,或者只是有人指出“嘿,这是一个错字”。无论如何,我都想确保这一点已经明确。
Playground链接到代码

1u4esq0p

1u4esq0p2#

看来我回答这个问题有点太快了。问题中提到的错误消息是由不正确的类型Assert引起的,正如@jcalz在the answer中所解释的那样。然而,这个答案仍然是有用的,因为它解释了为什么首先需要类型Assert。
当您尝试以下代码时:

a["Some Thing".toLowerCase().replace(/\s+/g, "")]

你会得到一个类型错误,因为a只有一个名为"something"的属性,而.toLowerCase().replace(...)的返回类型是string,而不是"something"。不幸的是,当您在字符串字面量上调用字符串方法时,TypeScript不会产生literal type。但是,有几个解决方案你可以尝试:
1.使用Template Literal Types特性创建自己的字符串操作函数,该函数确实返回文字类型:

type Whitespace = ' ' | '\n' | '\t' | '\r' | '\f';
type TrimAllWhitespace<S extends string> =
  S extends `${Whitespace}${infer Rest}`
    ? TrimAllWhitespace<Rest>
    : S extends `${infer NonWhitespace}${infer Rest}`
    ? `${NonWhitespace}${TrimAllWhitespace<Rest>}`
    : '';

function convert<T extends string>(x: T): TrimAllWhitespace<Lowercase<T>> {
  return x.toLowerCase().replace(/\s+/g, '') as TrimAllWhitespace<Lowercase<T>>;
}

const a = { something: true };

const App = () => <input type="checkbox" checked={a[convert('Some Thing')]} />;

1.强制类型转换为您已经知道的内容:

const a = { something: true };

const App = () => (
  <input
    type="checkbox"
    checked={
      a['Some Thing'.toLowerCase().replace(/\s+/g, '') as keyof typeof a]
    }
  />
);

1.在变量a处使用更轻松的输入

const a: Record<string, boolean | undefined> = { something: true };

const App = () => (
  <input
    type="checkbox"
    checked={a['Some Thing'.toLowerCase().replace(/\s+/g, '')]}
  />
);

相关问题