Keyof 推断字符串 |键只是字符串时的数字
Posted
技术标签:
【中文标题】Keyof 推断字符串 |键只是字符串时的数字【英文标题】:Keyof inferring string | number when key is only a string 【发布时间】:2019-01-19 08:20:24 【问题描述】:我这样定义AbstractModel
:
export interface AbstractModel
[key: string]: any
然后我声明类型Keys
:
export type Keys = keyof AbstractModel;
我希望任何具有 Keys 类型的东西都会被明确地解释为字符串,例如:
const test: Keys;
test.toLowercase(); // Error: Property 'toLowerCase' does not exist on type 'string | number'. Property 'toLowerCase' does not exist on type 'number'.
这是 Typescript (2.9.2) 的错误,还是我遗漏了什么?
【问题讨论】:
【参考方案1】:根据 TypeScript 2.9 的发行说明中的定义,如果您对带有字符串索引签名的接口进行 keyof,它将返回字符串和数字的联合
给定一个对象类型 X,keyof X 的解析如下:
如果 X 包含字符串索引签名,则 keyof X 是字符串、数字和表示类符号属性的文字类型的并集,否则
如果 X 包含数字索引签名,则 keyof X 是数字和表示类字符串和类符号属性的文字类型的并集,否则
keyof X 是表示类字符串、类数字和类符号属性的文字类型的联合。
source
这是因为:javascript 在索引对象时会将数字转换为字符串:
[..] 使用数字索引时,JavaScript 实际上会在索引到对象之前将其转换为字符串。这意味着使用 100(一个数字)进行索引与使用“100”(一个字符串)进行索引是一回事,因此两者需要保持一致。
source
例子:
let abc: AbstractModel =
1: "one",
;
console.log(abc[1] === abc["1"]); // true
当您只需要字符串键时,您只能从界面中提取字符串键,如下所示:
type StringKeys = Extract<keyof AbstractModel, string>;
const test: StringKeys;
test.toLowerCase(); // no error
TypeScript 编译器还提供了一个选项来获取 keyof
的 2.9 之前的行为:
keyofStringsOnly (boolean) 默认
false
仅将
keyof
解析为字符串值的属性名称(无数字或符号)。
source
【讨论】:
【参考方案2】:我也遇到过类似的问题。我通过强制 key 为字符串来解决它:
export type Keys = keyof AbstractModel & string;
其他选项是将密钥转换为字符串:test.toString().toLowercase()
【讨论】:
非常有用,非常适合全局设置keyofStringsOnly: true
选项。
嗯...那么为什么这不适用于type PickNumericProperties<T> = Pick<T, keyof [k: keyof T]: number>
?
这和Extract<keyof AbstractModel, string>
有什么实际区别吗??【参考方案3】:
对于通用打字稿实用程序,您可以使用以下内容:
type KeyOf<T extends object> = Extract<keyof T, string>;
用法:
const sym = Symbol();
const obj =
[sym]: true,
foo: 'foobar',
bar: 'barfoo',
1: 'lorem'
let key: KeyOf<typeof obj> = 'foo'; // 'foo' | 'bar'
key = 'bar'; // ok
key = 'fool'; // error
key = 1; // error
playground
【讨论】:
以上是关于Keyof 推断字符串 |键只是字符串时的数字的主要内容,如果未能解决你的问题,请参考以下文章
如何使 TypeScript 字符串枚举适用于字符串文字并正确进行类型推断
为啥打字稿不能用 <T extends Person, K extends keyof T> generic 正确推断 T[K]?