TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Number-like string keys become numbers after compiling to type declarations

Open calebmer opened this issue 3 years ago • 1 comments

Bug Report

TypeScript outputs an object with string keys that can be parsed as numbers ({"1": T}) as an object with number keys when processed by an object map (output is {1: T} after object map).

When you do keyof on the object type with string keys after an object map, you get the keys back as strings as expected ("1"). However, if you keyof on the object type TypeScript outputs to a .d.ts file you get back a number (1).

I ran into this when moving some code between TypeScript projects. So it was consuming a generated .d.ts instead of the original type. So for some f(x) it works works as expected when x is in the same project as f but when f is in a different project to x there's an issue.

const source = {"1": 1, "2": 2, "3": 3};

declare function objectMap<T>(object: T): {[K in keyof T]: string};

export const result = objectMap(source);

declare function objectKeys<T>(object: T): keyof T;

// Type is `"1" | "2" | "3"`. Expected!
export const keys1 = objectKeys(result);

// This is the type you get for `result` when compiling to `.d.ts`.
// (See `.d.ts` output for confirmation.)
export declare const resultCopiedFromGeneratedDeclaration: {
    1: string;
    2: string;
    3: string;
};

// Type is `1 | 2 | 3`. Unexpected
export const keys2 = objectKeys(resultCopiedFromGeneratedDeclaration);

(Playground)

šŸ”Ž Search Terms

Object map turns string keys into numbers

šŸ•— Version & Regression Information

4.8.4

  • This is the behavior in every version I tried (I tried versions back to 3.3.3 in the playground)

āÆ Playground Link

Playground link with relevant code

šŸ’» Code

const source = {"1": 1, "2": 2, "3": 3};

declare function objectMap<T>(object: T): {[K in keyof T]: string};

export const result = objectMap(source);

declare function objectKeys<T>(object: T): keyof T;

// Type is `"1" | "2" | "3"`. Expected!
export const keys1 = objectKeys(result);

// This is the type you get for `result` when compiling to `.d.ts`.
// (See `.d.ts` output for confirmation.)
export declare const resultCopiedFromGeneratedDeclaration: {
    1: string;
    2: string;
    3: string;
};

// Type is `1 | 2 | 3`. Unexpected
export const keys2 = objectKeys(resultCopiedFromGeneratedDeclaration);

šŸ™ Actual behavior

Type of keys2 is 1 | 2 | 3.

šŸ™‚ Expected behavior

Type of keys2 is "1" | "2" | "3" since that's the same as if the parameter to objectKeys() was in the same project and not imported from a .d.ts file.

I’d also be happy with {[K in keyof T as ``${K}``]: number} forcing the mapped object to have string keys instead of number keys.

calebmer avatar Nov 03 '22 03:11 calebmer

Duplicate of #50358. Used search terms: number string declaration in:title

MartinJohns avatar Nov 03 '22 07:11 MartinJohns

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

typescript-bot avatar Nov 06 '22 18:11 typescript-bot