我这样定义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)的错误,还是我缺少某些东西?
答案 0 :(得分:13)
如TypeScript 2.9发行说明中所定义,如果您对具有字符串索引签名的接口进行键控,则会返回字符串和数字的并集
给出对象类型X,X的键解析如下:
如果X包含字符串索引签名,则X的key是字符串,数字和表示符号型属性的文字类型的并集,否则
如果X包含数字索引签名,则X的key是数字和表示字符串型和符号型属性的文字类型的并集,否则
X的键是文字类型的并集,这些文字类型表示类似字符串,类似数字和类似符号的属性。
这是因为:索引对象时,JavaScript将数字转换为字符串:
[..]当用数字编制索引时,JavaScript实际上会在将其索引到对象之前将其转换为字符串。这意味着使用100(一个数字)进行索引与使用“ 100”(一个字符串)进行索引是同一回事,因此两者必须保持一致。
示例:
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(布尔值)默认
false
将
keyof
解析为仅字符串值的属性名称(无数字或符号)。
答案 1 :(得分: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
答案 2 :(得分:2)
我也遇到过类似的问题。我通过强制将键设置为字符串来解决它:
export type Keys = keyof AbstractModel & string;
其他选择是将密钥转换为字符串:test.toString().toLowercase()