From 1a27fd94e27e1235e70ae8b7be763c599a8246ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 19 Mar 2024 00:19:24 +0100 Subject: [PATCH 1/3] Fixed an issue with apparent mapped type keys --- src/compiler/checker.ts | 2 +- ... keyRemappingKeyofResult(strict=false).js} | 16 ++ ...emappingKeyofResult(strict=false).symbols} | 31 +++ ...yRemappingKeyofResult(strict=false).types} | 20 ++ .../keyRemappingKeyofResult(strict=true).js | 117 +++++++++ ...yRemappingKeyofResult(strict=true).symbols | 226 ++++++++++++++++++ ...keyRemappingKeyofResult(strict=true).types | 195 +++++++++++++++ .../cases/compiler/keyRemappingKeyofResult.ts | 14 ++ 8 files changed, 620 insertions(+), 1 deletion(-) rename tests/baselines/reference/{keyRemappingKeyofResult.js => keyRemappingKeyofResult(strict=false).js} (88%) rename tests/baselines/reference/{keyRemappingKeyofResult.symbols => keyRemappingKeyofResult(strict=false).symbols} (84%) rename tests/baselines/reference/{keyRemappingKeyofResult.types => keyRemappingKeyofResult(strict=false).types} (88%) create mode 100644 tests/baselines/reference/keyRemappingKeyofResult(strict=true).js create mode 100644 tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols create mode 100644 tests/baselines/reference/keyRemappingKeyofResult(strict=true).types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8ba4d7d896f8b..ac9d81329b73e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22486,7 +22486,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*stringsOnly*/ false, t => void mappedKeys.push(instantiateType(nameType, appendTypeMapping(targetType.mapper, getTypeParameterFromMappedType(targetType), t))), ); - return getUnionType(mappedKeys); + return mappedKeys.length ? getUnionType(mappedKeys) : stringNumberSymbolType; } function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, saveErrorInfo: ReturnType): Ternary { diff --git a/tests/baselines/reference/keyRemappingKeyofResult.js b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).js similarity index 88% rename from tests/baselines/reference/keyRemappingKeyofResult.js rename to tests/baselines/reference/keyRemappingKeyofResult(strict=false).js index 3b51e02dc735e..4107cfd488ca1 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult.js +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).js @@ -71,6 +71,19 @@ function g() { x = "str"; } +// https://github.com/microsoft/TypeScript/issues/57827 + +type StringKeys = Extract< + keyof { + [P in keyof T as T[P] extends string ? P : never]: any; + }, + string +>; + +function test_57827(z: StringKeys) { + const f: string = z; +} + export {}; //// [keyRemappingKeyofResult.js] @@ -98,4 +111,7 @@ function g() { x = sym; x = "str"; } +function test_57827(z) { + const f = z; +} export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult.symbols b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).symbols similarity index 84% rename from tests/baselines/reference/keyRemappingKeyofResult.symbols rename to tests/baselines/reference/keyRemappingKeyofResult(strict=false).symbols index 722c000f268fa..8e9cde0acfb91 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult.symbols +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).symbols @@ -192,4 +192,35 @@ function g() { >x : Symbol(x, Decl(keyRemappingKeyofResult.ts, 65, 7)) } +// https://github.com/microsoft/TypeScript/issues/57827 + +type StringKeys = Extract< +>StringKeys : Symbol(StringKeys, Decl(keyRemappingKeyofResult.ts, 68, 1)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 72, 16)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) + + keyof { + [P in keyof T as T[P] extends string ? P : never]: any; +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 74, 5)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 72, 16)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 72, 16)) +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 74, 5)) +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 74, 5)) + + }, + string +>; + +function test_57827(z: StringKeys) { +>test_57827 : Symbol(test_57827, Decl(keyRemappingKeyofResult.ts, 77, 2)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 79, 20)) +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 79, 23)) +>StringKeys : Symbol(StringKeys, Decl(keyRemappingKeyofResult.ts, 68, 1)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 79, 20)) + + const f: string = z; +>f : Symbol(f, Decl(keyRemappingKeyofResult.ts, 80, 7)) +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 79, 23)) +} + export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult.types b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).types similarity index 88% rename from tests/baselines/reference/keyRemappingKeyofResult.types rename to tests/baselines/reference/keyRemappingKeyofResult(strict=false).types index 01569ae0ddeed..07b898a527d1d 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult.types +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).types @@ -172,4 +172,24 @@ function g() { >"str" : "str" } +// https://github.com/microsoft/TypeScript/issues/57827 + +type StringKeys = Extract< +>StringKeys : StringKeys + + keyof { + [P in keyof T as T[P] extends string ? P : never]: any; + }, + string +>; + +function test_57827(z: StringKeys) { +>test_57827 : (z: StringKeys) => void +>z : Extract + + const f: string = z; +>f : string +>z : Extract +} + export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).js b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).js new file mode 100644 index 0000000000000..4107cfd488ca1 --- /dev/null +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).js @@ -0,0 +1,117 @@ +//// [tests/cases/compiler/keyRemappingKeyofResult.ts] //// + +//// [keyRemappingKeyofResult.ts] +const sym = Symbol("") +type Orig = { [k: string]: any, str: any, [sym]: any } + +type Okay = Exclude +// type Okay = string | number | typeof sym + +type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } +/* type Remapped = { + str: any; + [sym]: any; +} */ +// no string index signature, right? + +type Oops = Exclude +declare let x: Oops; +x = sym; +x = "str"; +// type Oops = typeof sym <-- what happened to "str"? + +// equivalently, with an unresolved generic (no `exclude` shenanigans, since conditions won't execute): +function f() { + type Orig = { [k: string]: any, str: any, [sym]: any } & T; + + type Okay = keyof Orig; + let a: Okay; + a = "str"; + a = sym; + a = "whatever"; + // type Okay = string | number | typeof sym + + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = keyof Remapped; + let x: Oops; + x = sym; + x = "str"; +} + +// and another generic case with a _distributive_ mapping, to trigger a different branch in `getIndexType` +function g() { + type Orig = { [k: string]: any, str: any, [sym]: any } & T; + + type Okay = keyof Orig; + let a: Okay; + a = "str"; + a = sym; + a = "whatever"; + // type Okay = string | number | typeof sym + + type NonIndex = {} extends Record ? never : T; + type DistributiveNonIndex = T extends unknown ? NonIndex : never; + + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = keyof Remapped; + let x: Oops; + x = sym; + x = "str"; +} + +// https://github.com/microsoft/TypeScript/issues/57827 + +type StringKeys = Extract< + keyof { + [P in keyof T as T[P] extends string ? P : never]: any; + }, + string +>; + +function test_57827(z: StringKeys) { + const f: string = z; +} + +export {}; + +//// [keyRemappingKeyofResult.js] +const sym = Symbol(""); +x = sym; +x = "str"; +// type Oops = typeof sym <-- what happened to "str"? +// equivalently, with an unresolved generic (no `exclude` shenanigans, since conditions won't execute): +function f() { + let a; + a = "str"; + a = sym; + a = "whatever"; + let x; + x = sym; + x = "str"; +} +// and another generic case with a _distributive_ mapping, to trigger a different branch in `getIndexType` +function g() { + let a; + a = "str"; + a = sym; + a = "whatever"; + let x; + x = sym; + x = "str"; +} +function test_57827(z) { + const f = z; +} +export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols new file mode 100644 index 0000000000000..8e9cde0acfb91 --- /dev/null +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols @@ -0,0 +1,226 @@ +//// [tests/cases/compiler/keyRemappingKeyofResult.ts] //// + +=== keyRemappingKeyofResult.ts === +const sym = Symbol("") +>sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) + +type Orig = { [k: string]: any, str: any, [sym]: any } +>Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 0, 22)) +>k : Symbol(k, Decl(keyRemappingKeyofResult.ts, 1, 15)) +>str : Symbol(str, Decl(keyRemappingKeyofResult.ts, 1, 31)) +>[sym] : Symbol([sym], Decl(keyRemappingKeyofResult.ts, 1, 41)) +>sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) + +type Okay = Exclude +>Okay : Symbol(Okay, Decl(keyRemappingKeyofResult.ts, 1, 54)) +>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --)) +>Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 0, 22)) + +// type Okay = string | number | typeof sym + +type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } +>Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 3, 38)) +>K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 6, 19)) +>Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 0, 22)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 6, 19)) +>K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 6, 19)) + +/* type Remapped = { + str: any; + [sym]: any; +} */ +// no string index signature, right? + +type Oops = Exclude +>Oops : Symbol(Oops, Decl(keyRemappingKeyofResult.ts, 6, 83)) +>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --)) +>Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 3, 38)) + +declare let x: Oops; +>x : Symbol(x, Decl(keyRemappingKeyofResult.ts, 14, 11)) +>Oops : Symbol(Oops, Decl(keyRemappingKeyofResult.ts, 6, 83)) + +x = sym; +>x : Symbol(x, Decl(keyRemappingKeyofResult.ts, 14, 11)) +>sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) + +x = "str"; +>x : Symbol(x, Decl(keyRemappingKeyofResult.ts, 14, 11)) + +// type Oops = typeof sym <-- what happened to "str"? + +// equivalently, with an unresolved generic (no `exclude` shenanigans, since conditions won't execute): +function f() { +>f : Symbol(f, Decl(keyRemappingKeyofResult.ts, 16, 10)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 20, 11)) + + type Orig = { [k: string]: any, str: any, [sym]: any } & T; +>Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 20, 17)) +>k : Symbol(k, Decl(keyRemappingKeyofResult.ts, 21, 19)) +>str : Symbol(str, Decl(keyRemappingKeyofResult.ts, 21, 35)) +>[sym] : Symbol([sym], Decl(keyRemappingKeyofResult.ts, 21, 45)) +>sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 20, 11)) + + type Okay = keyof Orig; +>Okay : Symbol(Okay, Decl(keyRemappingKeyofResult.ts, 21, 63)) +>Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 20, 17)) + + let a: Okay; +>a : Symbol(a, Decl(keyRemappingKeyofResult.ts, 24, 7)) +>Okay : Symbol(Okay, Decl(keyRemappingKeyofResult.ts, 21, 63)) + + a = "str"; +>a : Symbol(a, Decl(keyRemappingKeyofResult.ts, 24, 7)) + + a = sym; +>a : Symbol(a, Decl(keyRemappingKeyofResult.ts, 24, 7)) +>sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) + + a = "whatever"; +>a : Symbol(a, Decl(keyRemappingKeyofResult.ts, 24, 7)) + + // type Okay = string | number | typeof sym + + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } +>Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 27, 19)) +>K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 30, 23)) +>Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 20, 17)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 30, 23)) +>K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 30, 23)) + + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = keyof Remapped; +>Oops : Symbol(Oops, Decl(keyRemappingKeyofResult.ts, 30, 87)) +>Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 27, 19)) + + let x: Oops; +>x : Symbol(x, Decl(keyRemappingKeyofResult.ts, 38, 7)) +>Oops : Symbol(Oops, Decl(keyRemappingKeyofResult.ts, 30, 87)) + + x = sym; +>x : Symbol(x, Decl(keyRemappingKeyofResult.ts, 38, 7)) +>sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) + + x = "str"; +>x : Symbol(x, Decl(keyRemappingKeyofResult.ts, 38, 7)) +} + +// and another generic case with a _distributive_ mapping, to trigger a different branch in `getIndexType` +function g() { +>g : Symbol(g, Decl(keyRemappingKeyofResult.ts, 41, 1)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 44, 11)) + + type Orig = { [k: string]: any, str: any, [sym]: any } & T; +>Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 44, 17)) +>k : Symbol(k, Decl(keyRemappingKeyofResult.ts, 45, 19)) +>str : Symbol(str, Decl(keyRemappingKeyofResult.ts, 45, 35)) +>[sym] : Symbol([sym], Decl(keyRemappingKeyofResult.ts, 45, 45)) +>sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 44, 11)) + + type Okay = keyof Orig; +>Okay : Symbol(Okay, Decl(keyRemappingKeyofResult.ts, 45, 63)) +>Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 44, 17)) + + let a: Okay; +>a : Symbol(a, Decl(keyRemappingKeyofResult.ts, 48, 7)) +>Okay : Symbol(Okay, Decl(keyRemappingKeyofResult.ts, 45, 63)) + + a = "str"; +>a : Symbol(a, Decl(keyRemappingKeyofResult.ts, 48, 7)) + + a = sym; +>a : Symbol(a, Decl(keyRemappingKeyofResult.ts, 48, 7)) +>sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) + + a = "whatever"; +>a : Symbol(a, Decl(keyRemappingKeyofResult.ts, 48, 7)) + + // type Okay = string | number | typeof sym + + type NonIndex = {} extends Record ? never : T; +>NonIndex : Symbol(NonIndex, Decl(keyRemappingKeyofResult.ts, 51, 19)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 54, 18)) +>PropertyKey : Symbol(PropertyKey, Decl(lib.es5.d.ts, --, --)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 54, 18)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 54, 18)) + + type DistributiveNonIndex = T extends unknown ? NonIndex : never; +>DistributiveNonIndex : Symbol(DistributiveNonIndex, Decl(keyRemappingKeyofResult.ts, 54, 81)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 55, 30)) +>PropertyKey : Symbol(PropertyKey, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 55, 30)) +>NonIndex : Symbol(NonIndex, Decl(keyRemappingKeyofResult.ts, 51, 19)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 55, 30)) + + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } +>Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 55, 95)) +>K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 57, 23)) +>Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 44, 17)) +>DistributiveNonIndex : Symbol(DistributiveNonIndex, Decl(keyRemappingKeyofResult.ts, 54, 81)) +>K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 57, 23)) + + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = keyof Remapped; +>Oops : Symbol(Oops, Decl(keyRemappingKeyofResult.ts, 57, 73)) +>Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 55, 95)) + + let x: Oops; +>x : Symbol(x, Decl(keyRemappingKeyofResult.ts, 65, 7)) +>Oops : Symbol(Oops, Decl(keyRemappingKeyofResult.ts, 57, 73)) + + x = sym; +>x : Symbol(x, Decl(keyRemappingKeyofResult.ts, 65, 7)) +>sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) + + x = "str"; +>x : Symbol(x, Decl(keyRemappingKeyofResult.ts, 65, 7)) +} + +// https://github.com/microsoft/TypeScript/issues/57827 + +type StringKeys = Extract< +>StringKeys : Symbol(StringKeys, Decl(keyRemappingKeyofResult.ts, 68, 1)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 72, 16)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) + + keyof { + [P in keyof T as T[P] extends string ? P : never]: any; +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 74, 5)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 72, 16)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 72, 16)) +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 74, 5)) +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 74, 5)) + + }, + string +>; + +function test_57827(z: StringKeys) { +>test_57827 : Symbol(test_57827, Decl(keyRemappingKeyofResult.ts, 77, 2)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 79, 20)) +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 79, 23)) +>StringKeys : Symbol(StringKeys, Decl(keyRemappingKeyofResult.ts, 68, 1)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 79, 20)) + + const f: string = z; +>f : Symbol(f, Decl(keyRemappingKeyofResult.ts, 80, 7)) +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 79, 23)) +} + +export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).types b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).types new file mode 100644 index 0000000000000..07b898a527d1d --- /dev/null +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).types @@ -0,0 +1,195 @@ +//// [tests/cases/compiler/keyRemappingKeyofResult.ts] //// + +=== keyRemappingKeyofResult.ts === +const sym = Symbol("") +>sym : unique symbol +>Symbol("") : unique symbol +>Symbol : SymbolConstructor +>"" : "" + +type Orig = { [k: string]: any, str: any, [sym]: any } +>Orig : { [k: string]: any; str: any; [sym]: any; } +>k : string +>str : any +>[sym] : any +>sym : unique symbol + +type Okay = Exclude +>Okay : string | number | unique symbol + +// type Okay = string | number | typeof sym + +type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } +>Remapped : { str: any; [sym]: any; } + +/* type Remapped = { + str: any; + [sym]: any; +} */ +// no string index signature, right? + +type Oops = Exclude +>Oops : unique symbol | "str" + +declare let x: Oops; +>x : Oops + +x = sym; +>x = sym : unique symbol +>x : Oops +>sym : unique symbol + +x = "str"; +>x = "str" : "str" +>x : Oops +>"str" : "str" + +// type Oops = typeof sym <-- what happened to "str"? + +// equivalently, with an unresolved generic (no `exclude` shenanigans, since conditions won't execute): +function f() { +>f : () => void + + type Orig = { [k: string]: any, str: any, [sym]: any } & T; +>Orig : { [k: string]: any; str: any; [sym]: any; } & T +>k : string +>str : any +>[sym] : any +>sym : unique symbol + + type Okay = keyof Orig; +>Okay : string | number | unique symbol | keyof T + + let a: Okay; +>a : string | number | unique symbol | keyof T + + a = "str"; +>a = "str" : "str" +>a : string | number | unique symbol | keyof T +>"str" : "str" + + a = sym; +>a = sym : unique symbol +>a : string | number | unique symbol | keyof T +>sym : unique symbol + + a = "whatever"; +>a = "whatever" : "whatever" +>a : string | number | unique symbol | keyof T +>"whatever" : "whatever" + + // type Okay = string | number | typeof sym + + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } +>Remapped : { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as {} extends Record ? never : K]: any; } + + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = keyof Remapped; +>Oops : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as {} extends Record ? never : K]: any; } + + let x: Oops; +>x : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as {} extends Record ? never : K]: any; } + + x = sym; +>x = sym : unique symbol +>x : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as {} extends Record ? never : K]: any; } +>sym : unique symbol + + x = "str"; +>x = "str" : "str" +>x : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as {} extends Record ? never : K]: any; } +>"str" : "str" +} + +// and another generic case with a _distributive_ mapping, to trigger a different branch in `getIndexType` +function g() { +>g : () => void + + type Orig = { [k: string]: any, str: any, [sym]: any } & T; +>Orig : { [k: string]: any; str: any; [sym]: any; } & T +>k : string +>str : any +>[sym] : any +>sym : unique symbol + + type Okay = keyof Orig; +>Okay : string | number | unique symbol | keyof T + + let a: Okay; +>a : string | number | unique symbol | keyof T + + a = "str"; +>a = "str" : "str" +>a : string | number | unique symbol | keyof T +>"str" : "str" + + a = sym; +>a = sym : unique symbol +>a : string | number | unique symbol | keyof T +>sym : unique symbol + + a = "whatever"; +>a = "whatever" : "whatever" +>a : string | number | unique symbol | keyof T +>"whatever" : "whatever" + + // type Okay = string | number | typeof sym + + type NonIndex = {} extends Record ? never : T; +>NonIndex : {} extends Record ? never : T + + type DistributiveNonIndex = T extends unknown ? NonIndex : never; +>DistributiveNonIndex : T extends unknown ? {} extends Record ? never : T : never + + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } +>Remapped : { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as K extends unknown ? {} extends Record ? never : K : never]: any; } + + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = keyof Remapped; +>Oops : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as K extends unknown ? {} extends Record ? never : K : never]: any; } + + let x: Oops; +>x : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as K extends unknown ? {} extends Record ? never : K : never]: any; } + + x = sym; +>x = sym : unique symbol +>x : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as K extends unknown ? {} extends Record ? never : K : never]: any; } +>sym : unique symbol + + x = "str"; +>x = "str" : "str" +>x : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as K extends unknown ? {} extends Record ? never : K : never]: any; } +>"str" : "str" +} + +// https://github.com/microsoft/TypeScript/issues/57827 + +type StringKeys = Extract< +>StringKeys : StringKeys + + keyof { + [P in keyof T as T[P] extends string ? P : never]: any; + }, + string +>; + +function test_57827(z: StringKeys) { +>test_57827 : (z: StringKeys) => void +>z : Extract + + const f: string = z; +>f : string +>z : Extract +} + +export {}; diff --git a/tests/cases/compiler/keyRemappingKeyofResult.ts b/tests/cases/compiler/keyRemappingKeyofResult.ts index fcf3f835ac691..c376f0662a21c 100644 --- a/tests/cases/compiler/keyRemappingKeyofResult.ts +++ b/tests/cases/compiler/keyRemappingKeyofResult.ts @@ -1,3 +1,4 @@ +// @strict: true, false // @target: es6 const sym = Symbol("") type Orig = { [k: string]: any, str: any, [sym]: any } @@ -69,4 +70,17 @@ function g() { x = "str"; } +// https://github.com/microsoft/TypeScript/issues/57827 + +type StringKeys = Extract< + keyof { + [P in keyof T as T[P] extends string ? P : never]: any; + }, + string +>; + +function test_57827(z: StringKeys) { + const f: string = z; +} + export {}; \ No newline at end of file From 04976bff8e0e58fa00c5ceff8d630586168be098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 25 Nov 2024 00:13:09 +0100 Subject: [PATCH 2/3] improve the fix --- src/compiler/checker.ts | 21 +++- ...appingKeyofResult(strict=false).errors.txt | 105 ++++++++++++++++++ .../keyRemappingKeyofResult(strict=false).js | 28 +++-- ...RemappingKeyofResult(strict=false).symbols | 40 ++++++- ...eyRemappingKeyofResult(strict=false).types | 49 +++++++- ...mappingKeyofResult(strict=true).errors.txt | 105 ++++++++++++++++++ .../keyRemappingKeyofResult(strict=true).js | 28 +++-- ...yRemappingKeyofResult(strict=true).symbols | 40 ++++++- ...keyRemappingKeyofResult(strict=true).types | 49 +++++++- .../cases/compiler/keyRemappingKeyofResult.ts | 23 ++-- 10 files changed, 438 insertions(+), 50 deletions(-) create mode 100644 tests/baselines/reference/keyRemappingKeyofResult(strict=false).errors.txt create mode 100644 tests/baselines/reference/keyRemappingKeyofResult(strict=true).errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fa0483015faca..a33516c702fc3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22895,16 +22895,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function getApparentMappedTypeKeys(nameType: Type, targetType: MappedType) { - const modifiersType = getApparentType(getModifiersTypeFromMappedType(targetType)); + function getApparentMappedTypeKeys(nameType: Type, mappedType: MappedType) { + const modifiersType = getApparentType(getModifiersTypeFromMappedType(mappedType)); const mappedKeys: Type[] = []; forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( modifiersType, TypeFlags.StringOrNumberLiteralOrUnique, /*stringsOnly*/ false, - t => void mappedKeys.push(instantiateType(nameType, appendTypeMapping(targetType.mapper, getTypeParameterFromMappedType(targetType), t))), + t => void mappedKeys.push(instantiateType(nameType, appendTypeMapping(mappedType.mapper, getTypeParameterFromMappedType(mappedType), t))), ); - return mappedKeys.length ? getUnionType(mappedKeys) : stringNumberSymbolType; + return getUnionType(mappedKeys); } function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, saveErrorInfo: ReturnType): Ternary { @@ -23277,7 +23277,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // allow assignments of index types of identical (or similar enough) mapped types. // eg, `keyof {[X in keyof A]: Obj[X]}` should be assignable to `keyof {[Y in keyof A]: Tup[Y]}` because both map over the same set of keys (`keyof A`). // Without this source-side breakdown, a `keyof {[X in keyof A]: Obj[X]}` style type won't be assignable to anything except itself, which is much too strict. - const sourceMappedKeys = nameType && isMappedTypeWithKeyofConstraintDeclaration(mappedType) ? getApparentMappedTypeKeys(nameType, mappedType) : (nameType || getConstraintTypeFromMappedType(mappedType)); + let sourceMappedKeys: Type; + if (nameType && isMappedTypeWithKeyofConstraintDeclaration(mappedType)) { + sourceMappedKeys = getApparentMappedTypeKeys(nameType, mappedType); + if (sourceMappedKeys.flags & TypeFlags.Never) { + // modifiers type of mapped type is often `unknown`, `keyof unknown` is `never` and that's assignable to everything + // letting this through is too permissive so we use the apparent type of an index type here instead + sourceMappedKeys = stringNumberSymbolType; + } + } + else { + sourceMappedKeys = nameType || getConstraintTypeFromMappedType(mappedType); + } if (result = isRelatedTo(sourceMappedKeys, target, RecursionFlags.Source, reportErrors)) { return result; } diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).errors.txt b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).errors.txt new file mode 100644 index 0000000000000..5f69889fa7e76 --- /dev/null +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).errors.txt @@ -0,0 +1,105 @@ +keyRemappingKeyofResult.ts(82,3): error TS2322: Type 'string' is not assignable to type 'Extract'. +keyRemappingKeyofResult.ts(90,3): error TS2322: Type 'string' is not assignable to type 'keyof { [P in keyof T as T[P] extends string ? P : never]: any; }'. + Type 'string' is not assignable to type 'T[P] extends string ? P : never'. + + +==== keyRemappingKeyofResult.ts (2 errors) ==== + const sym = Symbol("") + type Orig = { [k: string]: any, str: any, [sym]: any } + + type Okay = Exclude + // type Okay = string | number | typeof sym + + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = Exclude + declare let x: Oops; + x = sym; + x = "str"; + // type Oops = typeof sym <-- what happened to "str"? + + // equivalently, with an unresolved generic (no `exclude` shenanigans, since conditions won't execute): + function f() { + type Orig = { [k: string]: any, str: any, [sym]: any } & T; + + type Okay = keyof Orig; + let a: Okay; + a = "str"; + a = sym; + a = "whatever"; + // type Okay = string | number | typeof sym + + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = keyof Remapped; + let x: Oops; + x = sym; + x = "str"; + } + + // and another generic case with a _distributive_ mapping, to trigger a different branch in `getIndexType` + function g() { + type Orig = { [k: string]: any, str: any, [sym]: any } & T; + + type Okay = keyof Orig; + let a: Okay; + a = "str"; + a = sym; + a = "whatever"; + // type Okay = string | number | typeof sym + + type NonIndex = {} extends Record ? never : T; + type DistributiveNonIndex = T extends unknown ? NonIndex : never; + + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = keyof Remapped; + let x: Oops; + x = sym; + x = "str"; + } + + // https://github.com/microsoft/TypeScript/issues/57827 + + type StringKeys = Extract< + keyof { + [P in keyof T as T[P] extends string ? P : never]: any; + }, + string + >; + + function test_57827(z: StringKeys) { + const f: string = z; + z = "foo"; // error + ~ +!!! error TS2322: Type 'string' is not assignable to type 'Extract'. + } + + type StringKeys2 = keyof { + [P in keyof T as T[P] extends string ? P : never]: any; + }; + + function h(z: StringKeys2) { + z = "foo"; // error + ~ +!!! error TS2322: Type 'string' is not assignable to type 'keyof { [P in keyof T as T[P] extends string ? P : never]: any; }'. +!!! error TS2322: Type 'string' is not assignable to type 'T[P] extends string ? P : never'. + } + + export {}; + \ No newline at end of file diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).js b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).js index 4107cfd488ca1..7169b9e7ef77d 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).js +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).js @@ -23,21 +23,21 @@ x = "str"; // equivalently, with an unresolved generic (no `exclude` shenanigans, since conditions won't execute): function f() { type Orig = { [k: string]: any, str: any, [sym]: any } & T; - + type Okay = keyof Orig; let a: Okay; a = "str"; a = sym; a = "whatever"; // type Okay = string | number | typeof sym - + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } /* type Remapped = { str: any; [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; let x: Oops; x = sym; @@ -47,7 +47,7 @@ function f() { // and another generic case with a _distributive_ mapping, to trigger a different branch in `getIndexType` function g() { type Orig = { [k: string]: any, str: any, [sym]: any } & T; - + type Okay = keyof Orig; let a: Okay; a = "str"; @@ -57,14 +57,14 @@ function g() { type NonIndex = {} extends Record ? never : T; type DistributiveNonIndex = T extends unknown ? NonIndex : never; - + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } /* type Remapped = { str: any; [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; let x: Oops; x = sym; @@ -82,9 +82,19 @@ type StringKeys = Extract< function test_57827(z: StringKeys) { const f: string = z; + z = "foo"; // error } -export {}; +type StringKeys2 = keyof { + [P in keyof T as T[P] extends string ? P : never]: any; +}; + +function h(z: StringKeys2) { + z = "foo"; // error +} + +export {}; + //// [keyRemappingKeyofResult.js] const sym = Symbol(""); @@ -113,5 +123,9 @@ function g() { } function test_57827(z) { const f = z; + z = "foo"; // error +} +function h(z) { + z = "foo"; // error } export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).symbols b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).symbols index 8e9cde0acfb91..8e49e52eab8a4 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).symbols +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).symbols @@ -63,7 +63,7 @@ function f() { >[sym] : Symbol([sym], Decl(keyRemappingKeyofResult.ts, 21, 45)) >sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) >T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 20, 11)) - + type Okay = keyof Orig; >Okay : Symbol(Okay, Decl(keyRemappingKeyofResult.ts, 21, 63)) >Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 20, 17)) @@ -83,7 +83,7 @@ function f() { >a : Symbol(a, Decl(keyRemappingKeyofResult.ts, 24, 7)) // type Okay = string | number | typeof sym - + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } >Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 27, 19)) >K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 30, 23)) @@ -97,7 +97,7 @@ function f() { [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; >Oops : Symbol(Oops, Decl(keyRemappingKeyofResult.ts, 30, 87)) >Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 27, 19)) @@ -126,7 +126,7 @@ function g() { >[sym] : Symbol([sym], Decl(keyRemappingKeyofResult.ts, 45, 45)) >sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) >T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 44, 11)) - + type Okay = keyof Orig; >Okay : Symbol(Okay, Decl(keyRemappingKeyofResult.ts, 45, 63)) >Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 44, 17)) @@ -162,7 +162,7 @@ function g() { >T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 55, 30)) >NonIndex : Symbol(NonIndex, Decl(keyRemappingKeyofResult.ts, 51, 19)) >T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 55, 30)) - + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } >Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 55, 95)) >K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 57, 23)) @@ -175,7 +175,7 @@ function g() { [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; >Oops : Symbol(Oops, Decl(keyRemappingKeyofResult.ts, 57, 73)) >Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 55, 95)) @@ -220,7 +220,35 @@ function test_57827(z: StringKeys) { const f: string = z; >f : Symbol(f, Decl(keyRemappingKeyofResult.ts, 80, 7)) +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 79, 23)) + + z = "foo"; // error >z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 79, 23)) } +type StringKeys2 = keyof { +>StringKeys2 : Symbol(StringKeys2, Decl(keyRemappingKeyofResult.ts, 82, 1)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 84, 17)) + + [P in keyof T as T[P] extends string ? P : never]: any; +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 85, 3)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 84, 17)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 84, 17)) +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 85, 3)) +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 85, 3)) + +}; + +function h(z: StringKeys2) { +>h : Symbol(h, Decl(keyRemappingKeyofResult.ts, 86, 2)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 88, 11)) +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 88, 14)) +>StringKeys2 : Symbol(StringKeys2, Decl(keyRemappingKeyofResult.ts, 82, 1)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 88, 11)) + + z = "foo"; // error +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 88, 14)) +} + export {}; + diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).types b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).types index 8d3983d62f1eb..9dd85908b9966 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).types +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).types @@ -17,7 +17,9 @@ type Orig = { [k: string]: any, str: any, [sym]: any } >k : string > : ^^^^^^ >str : any +> : ^^^ >[sym] : any +> : ^^^ >sym : unique symbol > : ^^^^^^^^^^^^^ @@ -74,10 +76,12 @@ function f() { >k : string > : ^^^^^^ >str : any +> : ^^^ >[sym] : any +> : ^^^ >sym : unique symbol > : ^^^^^^^^^^^^^ - + type Okay = keyof Orig; >Okay : string | number | unique symbol | keyof T > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,7 +115,7 @@ function f() { > : ^^^^^^^^^^ // type Okay = string | number | typeof sym - + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } >Remapped : { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as {} extends Record ? never : K]: any; } > : ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +125,7 @@ function f() { [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; >Oops : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as {} extends Record ? never : K]: any; } > : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -158,10 +162,12 @@ function g() { >k : string > : ^^^^^^ >str : any +> : ^^^ >[sym] : any +> : ^^^ >sym : unique symbol > : ^^^^^^^^^^^^^ - + type Okay = keyof Orig; >Okay : string | number | unique symbol | keyof T > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -203,7 +209,7 @@ function g() { type DistributiveNonIndex = T extends unknown ? NonIndex : never; >DistributiveNonIndex : T extends unknown ? {} extends Record ? never : T : never > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } >Remapped : { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as K extends unknown ? {} extends Record ? never : K : never]: any; } > : ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -213,7 +219,7 @@ function g() { [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; >Oops : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as K extends unknown ? {} extends Record ? never : K : never]: any; } > : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -262,6 +268,37 @@ function test_57827(z: StringKeys) { > : ^^^^^^ >z : Extract > : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + z = "foo"; // error +>z = "foo" : "foo" +> : ^^^^^ +>z : Extract +> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>"foo" : "foo" +> : ^^^^^ +} + +type StringKeys2 = keyof { +>StringKeys2 : keyof { [P in keyof T as T[P] extends string ? P : never]: any; } +> : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + [P in keyof T as T[P] extends string ? P : never]: any; +}; + +function h(z: StringKeys2) { +>h : (z: StringKeys2) => void +> : ^ ^^ ^^ ^^^^^^^^^ +>z : keyof { [P in keyof T as T[P] extends string ? P : never]: any; } +> : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + z = "foo"; // error +>z = "foo" : "foo" +> : ^^^^^ +>z : keyof { [P in keyof T as T[P] extends string ? P : never]: any; } +> : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>"foo" : "foo" +> : ^^^^^ } export {}; + diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).errors.txt b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).errors.txt new file mode 100644 index 0000000000000..5f69889fa7e76 --- /dev/null +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).errors.txt @@ -0,0 +1,105 @@ +keyRemappingKeyofResult.ts(82,3): error TS2322: Type 'string' is not assignable to type 'Extract'. +keyRemappingKeyofResult.ts(90,3): error TS2322: Type 'string' is not assignable to type 'keyof { [P in keyof T as T[P] extends string ? P : never]: any; }'. + Type 'string' is not assignable to type 'T[P] extends string ? P : never'. + + +==== keyRemappingKeyofResult.ts (2 errors) ==== + const sym = Symbol("") + type Orig = { [k: string]: any, str: any, [sym]: any } + + type Okay = Exclude + // type Okay = string | number | typeof sym + + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = Exclude + declare let x: Oops; + x = sym; + x = "str"; + // type Oops = typeof sym <-- what happened to "str"? + + // equivalently, with an unresolved generic (no `exclude` shenanigans, since conditions won't execute): + function f() { + type Orig = { [k: string]: any, str: any, [sym]: any } & T; + + type Okay = keyof Orig; + let a: Okay; + a = "str"; + a = sym; + a = "whatever"; + // type Okay = string | number | typeof sym + + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = keyof Remapped; + let x: Oops; + x = sym; + x = "str"; + } + + // and another generic case with a _distributive_ mapping, to trigger a different branch in `getIndexType` + function g() { + type Orig = { [k: string]: any, str: any, [sym]: any } & T; + + type Okay = keyof Orig; + let a: Okay; + a = "str"; + a = sym; + a = "whatever"; + // type Okay = string | number | typeof sym + + type NonIndex = {} extends Record ? never : T; + type DistributiveNonIndex = T extends unknown ? NonIndex : never; + + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } + /* type Remapped = { + str: any; + [sym]: any; + } */ + // no string index signature, right? + + type Oops = keyof Remapped; + let x: Oops; + x = sym; + x = "str"; + } + + // https://github.com/microsoft/TypeScript/issues/57827 + + type StringKeys = Extract< + keyof { + [P in keyof T as T[P] extends string ? P : never]: any; + }, + string + >; + + function test_57827(z: StringKeys) { + const f: string = z; + z = "foo"; // error + ~ +!!! error TS2322: Type 'string' is not assignable to type 'Extract'. + } + + type StringKeys2 = keyof { + [P in keyof T as T[P] extends string ? P : never]: any; + }; + + function h(z: StringKeys2) { + z = "foo"; // error + ~ +!!! error TS2322: Type 'string' is not assignable to type 'keyof { [P in keyof T as T[P] extends string ? P : never]: any; }'. +!!! error TS2322: Type 'string' is not assignable to type 'T[P] extends string ? P : never'. + } + + export {}; + \ No newline at end of file diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).js b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).js index 4107cfd488ca1..7169b9e7ef77d 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).js +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).js @@ -23,21 +23,21 @@ x = "str"; // equivalently, with an unresolved generic (no `exclude` shenanigans, since conditions won't execute): function f() { type Orig = { [k: string]: any, str: any, [sym]: any } & T; - + type Okay = keyof Orig; let a: Okay; a = "str"; a = sym; a = "whatever"; // type Okay = string | number | typeof sym - + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } /* type Remapped = { str: any; [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; let x: Oops; x = sym; @@ -47,7 +47,7 @@ function f() { // and another generic case with a _distributive_ mapping, to trigger a different branch in `getIndexType` function g() { type Orig = { [k: string]: any, str: any, [sym]: any } & T; - + type Okay = keyof Orig; let a: Okay; a = "str"; @@ -57,14 +57,14 @@ function g() { type NonIndex = {} extends Record ? never : T; type DistributiveNonIndex = T extends unknown ? NonIndex : never; - + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } /* type Remapped = { str: any; [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; let x: Oops; x = sym; @@ -82,9 +82,19 @@ type StringKeys = Extract< function test_57827(z: StringKeys) { const f: string = z; + z = "foo"; // error } -export {}; +type StringKeys2 = keyof { + [P in keyof T as T[P] extends string ? P : never]: any; +}; + +function h(z: StringKeys2) { + z = "foo"; // error +} + +export {}; + //// [keyRemappingKeyofResult.js] const sym = Symbol(""); @@ -113,5 +123,9 @@ function g() { } function test_57827(z) { const f = z; + z = "foo"; // error +} +function h(z) { + z = "foo"; // error } export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols index 8e9cde0acfb91..8e49e52eab8a4 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols @@ -63,7 +63,7 @@ function f() { >[sym] : Symbol([sym], Decl(keyRemappingKeyofResult.ts, 21, 45)) >sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) >T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 20, 11)) - + type Okay = keyof Orig; >Okay : Symbol(Okay, Decl(keyRemappingKeyofResult.ts, 21, 63)) >Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 20, 17)) @@ -83,7 +83,7 @@ function f() { >a : Symbol(a, Decl(keyRemappingKeyofResult.ts, 24, 7)) // type Okay = string | number | typeof sym - + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } >Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 27, 19)) >K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 30, 23)) @@ -97,7 +97,7 @@ function f() { [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; >Oops : Symbol(Oops, Decl(keyRemappingKeyofResult.ts, 30, 87)) >Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 27, 19)) @@ -126,7 +126,7 @@ function g() { >[sym] : Symbol([sym], Decl(keyRemappingKeyofResult.ts, 45, 45)) >sym : Symbol(sym, Decl(keyRemappingKeyofResult.ts, 0, 5)) >T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 44, 11)) - + type Okay = keyof Orig; >Okay : Symbol(Okay, Decl(keyRemappingKeyofResult.ts, 45, 63)) >Orig : Symbol(Orig, Decl(keyRemappingKeyofResult.ts, 44, 17)) @@ -162,7 +162,7 @@ function g() { >T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 55, 30)) >NonIndex : Symbol(NonIndex, Decl(keyRemappingKeyofResult.ts, 51, 19)) >T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 55, 30)) - + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } >Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 55, 95)) >K : Symbol(K, Decl(keyRemappingKeyofResult.ts, 57, 23)) @@ -175,7 +175,7 @@ function g() { [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; >Oops : Symbol(Oops, Decl(keyRemappingKeyofResult.ts, 57, 73)) >Remapped : Symbol(Remapped, Decl(keyRemappingKeyofResult.ts, 55, 95)) @@ -220,7 +220,35 @@ function test_57827(z: StringKeys) { const f: string = z; >f : Symbol(f, Decl(keyRemappingKeyofResult.ts, 80, 7)) +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 79, 23)) + + z = "foo"; // error >z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 79, 23)) } +type StringKeys2 = keyof { +>StringKeys2 : Symbol(StringKeys2, Decl(keyRemappingKeyofResult.ts, 82, 1)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 84, 17)) + + [P in keyof T as T[P] extends string ? P : never]: any; +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 85, 3)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 84, 17)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 84, 17)) +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 85, 3)) +>P : Symbol(P, Decl(keyRemappingKeyofResult.ts, 85, 3)) + +}; + +function h(z: StringKeys2) { +>h : Symbol(h, Decl(keyRemappingKeyofResult.ts, 86, 2)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 88, 11)) +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 88, 14)) +>StringKeys2 : Symbol(StringKeys2, Decl(keyRemappingKeyofResult.ts, 82, 1)) +>T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 88, 11)) + + z = "foo"; // error +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 88, 14)) +} + export {}; + diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).types b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).types index 8d3983d62f1eb..9dd85908b9966 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).types +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).types @@ -17,7 +17,9 @@ type Orig = { [k: string]: any, str: any, [sym]: any } >k : string > : ^^^^^^ >str : any +> : ^^^ >[sym] : any +> : ^^^ >sym : unique symbol > : ^^^^^^^^^^^^^ @@ -74,10 +76,12 @@ function f() { >k : string > : ^^^^^^ >str : any +> : ^^^ >[sym] : any +> : ^^^ >sym : unique symbol > : ^^^^^^^^^^^^^ - + type Okay = keyof Orig; >Okay : string | number | unique symbol | keyof T > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,7 +115,7 @@ function f() { > : ^^^^^^^^^^ // type Okay = string | number | typeof sym - + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } >Remapped : { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as {} extends Record ? never : K]: any; } > : ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +125,7 @@ function f() { [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; >Oops : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as {} extends Record ? never : K]: any; } > : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -158,10 +162,12 @@ function g() { >k : string > : ^^^^^^ >str : any +> : ^^^ >[sym] : any +> : ^^^ >sym : unique symbol > : ^^^^^^^^^^^^^ - + type Okay = keyof Orig; >Okay : string | number | unique symbol | keyof T > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -203,7 +209,7 @@ function g() { type DistributiveNonIndex = T extends unknown ? NonIndex : never; >DistributiveNonIndex : T extends unknown ? {} extends Record ? never : T : never > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } >Remapped : { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as K extends unknown ? {} extends Record ? never : K : never]: any; } > : ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -213,7 +219,7 @@ function g() { [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; >Oops : keyof { [K in keyof ({ [k: string]: any; str: any; [sym]: any; } & T) as K extends unknown ? {} extends Record ? never : K : never]: any; } > : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -262,6 +268,37 @@ function test_57827(z: StringKeys) { > : ^^^^^^ >z : Extract > : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + z = "foo"; // error +>z = "foo" : "foo" +> : ^^^^^ +>z : Extract +> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>"foo" : "foo" +> : ^^^^^ +} + +type StringKeys2 = keyof { +>StringKeys2 : keyof { [P in keyof T as T[P] extends string ? P : never]: any; } +> : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + [P in keyof T as T[P] extends string ? P : never]: any; +}; + +function h(z: StringKeys2) { +>h : (z: StringKeys2) => void +> : ^ ^^ ^^ ^^^^^^^^^ +>z : keyof { [P in keyof T as T[P] extends string ? P : never]: any; } +> : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + z = "foo"; // error +>z = "foo" : "foo" +> : ^^^^^ +>z : keyof { [P in keyof T as T[P] extends string ? P : never]: any; } +> : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>"foo" : "foo" +> : ^^^^^ } export {}; + diff --git a/tests/cases/compiler/keyRemappingKeyofResult.ts b/tests/cases/compiler/keyRemappingKeyofResult.ts index c376f0662a21c..89f14004660ef 100644 --- a/tests/cases/compiler/keyRemappingKeyofResult.ts +++ b/tests/cases/compiler/keyRemappingKeyofResult.ts @@ -22,21 +22,21 @@ x = "str"; // equivalently, with an unresolved generic (no `exclude` shenanigans, since conditions won't execute): function f() { type Orig = { [k: string]: any, str: any, [sym]: any } & T; - + type Okay = keyof Orig; let a: Okay; a = "str"; a = sym; a = "whatever"; // type Okay = string | number | typeof sym - + type Remapped = { [K in keyof Orig as {} extends Record ? never : K]: any } /* type Remapped = { str: any; [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; let x: Oops; x = sym; @@ -46,7 +46,7 @@ function f() { // and another generic case with a _distributive_ mapping, to trigger a different branch in `getIndexType` function g() { type Orig = { [k: string]: any, str: any, [sym]: any } & T; - + type Okay = keyof Orig; let a: Okay; a = "str"; @@ -56,14 +56,14 @@ function g() { type NonIndex = {} extends Record ? never : T; type DistributiveNonIndex = T extends unknown ? NonIndex : never; - + type Remapped = { [K in keyof Orig as DistributiveNonIndex]: any } /* type Remapped = { str: any; [sym]: any; } */ // no string index signature, right? - + type Oops = keyof Remapped; let x: Oops; x = sym; @@ -81,6 +81,15 @@ type StringKeys = Extract< function test_57827(z: StringKeys) { const f: string = z; + z = "foo"; // error +} + +type StringKeys2 = keyof { + [P in keyof T as T[P] extends string ? P : never]: any; +}; + +function h(z: StringKeys2) { + z = "foo"; // error } -export {}; \ No newline at end of file +export {}; From cad532adfb753a6737111526120824443030e30b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 30 Nov 2024 16:21:32 +0100 Subject: [PATCH 3/3] add extra test case --- .../keyRemappingKeyofResult(strict=false).errors.txt | 1 + .../reference/keyRemappingKeyofResult(strict=false).js | 2 ++ .../reference/keyRemappingKeyofResult(strict=false).symbols | 4 ++++ .../reference/keyRemappingKeyofResult(strict=false).types | 6 ++++++ .../keyRemappingKeyofResult(strict=true).errors.txt | 1 + .../reference/keyRemappingKeyofResult(strict=true).js | 2 ++ .../reference/keyRemappingKeyofResult(strict=true).symbols | 4 ++++ .../reference/keyRemappingKeyofResult(strict=true).types | 6 ++++++ tests/cases/compiler/keyRemappingKeyofResult.ts | 1 + 9 files changed, 27 insertions(+) diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).errors.txt b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).errors.txt index 5f69889fa7e76..a072e3be92b17 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).errors.txt +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).errors.txt @@ -99,6 +99,7 @@ keyRemappingKeyofResult.ts(90,3): error TS2322: Type 'string' is not assignable ~ !!! error TS2322: Type 'string' is not assignable to type 'keyof { [P in keyof T as T[P] extends string ? P : never]: any; }'. !!! error TS2322: Type 'string' is not assignable to type 'T[P] extends string ? P : never'. + const f: string = z; // ok } export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).js b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).js index 7169b9e7ef77d..c46149d6c8d44 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).js +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).js @@ -91,6 +91,7 @@ type StringKeys2 = keyof { function h(z: StringKeys2) { z = "foo"; // error + const f: string = z; // ok } export {}; @@ -127,5 +128,6 @@ function test_57827(z) { } function h(z) { z = "foo"; // error + const f = z; // ok } export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).symbols b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).symbols index 8e49e52eab8a4..cea827e0f2f5c 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).symbols +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).symbols @@ -247,6 +247,10 @@ function h(z: StringKeys2) { >T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 88, 11)) z = "foo"; // error +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 88, 14)) + + const f: string = z; // ok +>f : Symbol(f, Decl(keyRemappingKeyofResult.ts, 90, 7)) >z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 88, 14)) } diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).types b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).types index 9dd85908b9966..83fe33b0104a2 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=false).types +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=false).types @@ -298,6 +298,12 @@ function h(z: StringKeys2) { > : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >"foo" : "foo" > : ^^^^^ + + const f: string = z; // ok +>f : string +> : ^^^^^^ +>z : string +> : ^^^^^^ } export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).errors.txt b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).errors.txt index 5f69889fa7e76..a072e3be92b17 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).errors.txt +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).errors.txt @@ -99,6 +99,7 @@ keyRemappingKeyofResult.ts(90,3): error TS2322: Type 'string' is not assignable ~ !!! error TS2322: Type 'string' is not assignable to type 'keyof { [P in keyof T as T[P] extends string ? P : never]: any; }'. !!! error TS2322: Type 'string' is not assignable to type 'T[P] extends string ? P : never'. + const f: string = z; // ok } export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).js b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).js index 7169b9e7ef77d..c46149d6c8d44 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).js +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).js @@ -91,6 +91,7 @@ type StringKeys2 = keyof { function h(z: StringKeys2) { z = "foo"; // error + const f: string = z; // ok } export {}; @@ -127,5 +128,6 @@ function test_57827(z) { } function h(z) { z = "foo"; // error + const f = z; // ok } export {}; diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols index 8e49e52eab8a4..cea827e0f2f5c 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).symbols @@ -247,6 +247,10 @@ function h(z: StringKeys2) { >T : Symbol(T, Decl(keyRemappingKeyofResult.ts, 88, 11)) z = "foo"; // error +>z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 88, 14)) + + const f: string = z; // ok +>f : Symbol(f, Decl(keyRemappingKeyofResult.ts, 90, 7)) >z : Symbol(z, Decl(keyRemappingKeyofResult.ts, 88, 14)) } diff --git a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).types b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).types index 9dd85908b9966..83fe33b0104a2 100644 --- a/tests/baselines/reference/keyRemappingKeyofResult(strict=true).types +++ b/tests/baselines/reference/keyRemappingKeyofResult(strict=true).types @@ -298,6 +298,12 @@ function h(z: StringKeys2) { > : ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >"foo" : "foo" > : ^^^^^ + + const f: string = z; // ok +>f : string +> : ^^^^^^ +>z : string +> : ^^^^^^ } export {}; diff --git a/tests/cases/compiler/keyRemappingKeyofResult.ts b/tests/cases/compiler/keyRemappingKeyofResult.ts index 89f14004660ef..2cec329384b29 100644 --- a/tests/cases/compiler/keyRemappingKeyofResult.ts +++ b/tests/cases/compiler/keyRemappingKeyofResult.ts @@ -90,6 +90,7 @@ type StringKeys2 = keyof { function h(z: StringKeys2) { z = "foo"; // error + const f: string = z; // ok } export {};