Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

typescript - Keyof inferring string | number when key is only a string

I define an AbstractModel like so:

export interface AbstractModel {
   [key: string]: any
}

Then I declare the type Keys:

export type Keys = keyof AbstractModel;

I would expect that anything with the Keys type would be interpreted univocally as a string, for example:

const test: Keys;
test.toLowercase(); // Error: Property 'toLowerCase' does not exist on type 'string | number'. Property 'toLowerCase' does not exist on type 'number'.

Is this a bug of Typescript (2.9.2), or am I missing something?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As defined in the Release Notes of TypeScript 2.9, if you keyof an interface with a string index signature it returns a union of string and number

Given an object type X, keyof X is resolved as follows:

If X contains a string index signature, keyof X is a union of string, number, and the literal types representing symbol-like properties, otherwise

If X contains a numeric index signature, keyof X is a union of number and the literal types representing string-like and symbol-like properties, otherwise

keyof X is a union of the literal types representing string-like, number-like, and symbol-like properties.

source

This is because: JavaScript converts numbers to strings when indexing an object:

[..] when indexing with a number, JavaScript will actually convert that to a string before indexing into an object. That means that indexing with 100 (a number) is the same thing as indexing with "100" (a string), so the two need to be consistent.

source

Example:

let abc: AbstractModel = {
    1: "one",
};

console.log(abc[1] === abc["1"]); // true

When you only want the string keys, then you could only extract the string keys from your interface like so:

type StringKeys = Extract<keyof AbstractModel, string>;

const test: StringKeys;
test.toLowerCase(); // no error

Also the TypeScript compiler provides an option to get the pre 2.9 behavior of keyof:

keyofStringsOnly (boolean) default false

Resolve keyof to string valued property names only (no numbers or symbols).

source


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...