diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 83d90529be8..05e53154056 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28997,6 +28997,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbol = getSymbolOfDeclaration(element); return getTypeOfPropertyOfContextualType(type, symbol.escapedName, getSymbolLinks(symbol).nameType); } + if (hasDynamicName(element)) { + const name = getNameOfDeclaration(element); + if (name && isComputedPropertyName(name)) { + const exprType = checkExpression(name.expression); + const propType = isTypeUsableAsPropertyName(exprType) && getTypeOfPropertyOfContextualType(type, getPropertyNameFromType(exprType)); + if (propType) { + return propType; + } + } + } if (element.name) { const nameType = getLiteralTypeFromPropertyName(element.name); // We avoid calling getApplicableIndexInfo here because it performs potentially expensive intersection reduction. diff --git a/tests/baselines/reference/contextualComputedNonBindablePropertyType.symbols b/tests/baselines/reference/contextualComputedNonBindablePropertyType.symbols new file mode 100644 index 00000000000..00fecd2dc75 --- /dev/null +++ b/tests/baselines/reference/contextualComputedNonBindablePropertyType.symbols @@ -0,0 +1,98 @@ +=== tests/cases/compiler/contextualComputedNonBindablePropertyType.ts === +// repro #51906 + +declare function testD(): "d"; +>testD : Symbol(testD, Decl(contextualComputedNonBindablePropertyType.ts, 0, 0)) + +declare function forceMatch(matched: { +>forceMatch : Symbol(forceMatch, Decl(contextualComputedNonBindablePropertyType.ts, 2, 30)) +>T : Symbol(T, Decl(contextualComputedNonBindablePropertyType.ts, 4, 28)) +>matched : Symbol(matched, Decl(contextualComputedNonBindablePropertyType.ts, 4, 31)) + + [key in keyof T]: key; +>key : Symbol(key, Decl(contextualComputedNonBindablePropertyType.ts, 5, 3)) +>T : Symbol(T, Decl(contextualComputedNonBindablePropertyType.ts, 4, 28)) +>key : Symbol(key, Decl(contextualComputedNonBindablePropertyType.ts, 5, 3)) + +}): void; + +forceMatch({ +>forceMatch : Symbol(forceMatch, Decl(contextualComputedNonBindablePropertyType.ts, 2, 30)) + + [testD()]: "d", +>[testD()] : Symbol([testD()], Decl(contextualComputedNonBindablePropertyType.ts, 8, 12)) +>testD : Symbol(testD, Decl(contextualComputedNonBindablePropertyType.ts, 0, 0)) + +}); + +declare function forceMatch2(matched: { +>forceMatch2 : Symbol(forceMatch2, Decl(contextualComputedNonBindablePropertyType.ts, 10, 3)) +>T : Symbol(T, Decl(contextualComputedNonBindablePropertyType.ts, 12, 29)) +>matched : Symbol(matched, Decl(contextualComputedNonBindablePropertyType.ts, 12, 32)) + + [key in keyof T]: ({ key }: { key: key }) => void; +>key : Symbol(key, Decl(contextualComputedNonBindablePropertyType.ts, 13, 3)) +>T : Symbol(T, Decl(contextualComputedNonBindablePropertyType.ts, 12, 29)) +>key : Symbol(key, Decl(contextualComputedNonBindablePropertyType.ts, 13, 22)) +>key : Symbol(key, Decl(contextualComputedNonBindablePropertyType.ts, 13, 31)) +>key : Symbol(key, Decl(contextualComputedNonBindablePropertyType.ts, 13, 3)) + +}): void; + +forceMatch2({ +>forceMatch2 : Symbol(forceMatch2, Decl(contextualComputedNonBindablePropertyType.ts, 10, 3)) + + [testD()]: ({ key }) => {}, +>[testD()] : Symbol([testD()], Decl(contextualComputedNonBindablePropertyType.ts, 16, 13)) +>testD : Symbol(testD, Decl(contextualComputedNonBindablePropertyType.ts, 0, 0)) +>key : Symbol(key, Decl(contextualComputedNonBindablePropertyType.ts, 17, 15)) + +}); + +// repro #52954 + +type Original = { foo: 'expects a string literal', baz: boolean, bar: number } +>Original : Symbol(Original, Decl(contextualComputedNonBindablePropertyType.ts, 18, 3)) +>foo : Symbol(foo, Decl(contextualComputedNonBindablePropertyType.ts, 22, 17)) +>baz : Symbol(baz, Decl(contextualComputedNonBindablePropertyType.ts, 22, 50)) +>bar : Symbol(bar, Decl(contextualComputedNonBindablePropertyType.ts, 22, 64)) + +type Mapped = { +>Mapped : Symbol(Mapped, Decl(contextualComputedNonBindablePropertyType.ts, 22, 78)) + + [prop in keyof Original]: (arg: Original[prop]) => Original[prop] +>prop : Symbol(prop, Decl(contextualComputedNonBindablePropertyType.ts, 25, 3)) +>Original : Symbol(Original, Decl(contextualComputedNonBindablePropertyType.ts, 18, 3)) +>arg : Symbol(arg, Decl(contextualComputedNonBindablePropertyType.ts, 25, 29)) +>Original : Symbol(Original, Decl(contextualComputedNonBindablePropertyType.ts, 18, 3)) +>prop : Symbol(prop, Decl(contextualComputedNonBindablePropertyType.ts, 25, 3)) +>Original : Symbol(Original, Decl(contextualComputedNonBindablePropertyType.ts, 18, 3)) +>prop : Symbol(prop, Decl(contextualComputedNonBindablePropertyType.ts, 25, 3)) +} + +const propSelector = (propName: propName): propName => propName; +>propSelector : Symbol(propSelector, Decl(contextualComputedNonBindablePropertyType.ts, 28, 5)) +>propName : Symbol(propName, Decl(contextualComputedNonBindablePropertyType.ts, 28, 23), Decl(contextualComputedNonBindablePropertyType.ts, 28, 48)) +>propName : Symbol(propName, Decl(contextualComputedNonBindablePropertyType.ts, 28, 23), Decl(contextualComputedNonBindablePropertyType.ts, 28, 48)) +>propName : Symbol(propName, Decl(contextualComputedNonBindablePropertyType.ts, 28, 23), Decl(contextualComputedNonBindablePropertyType.ts, 28, 48)) +>propName : Symbol(propName, Decl(contextualComputedNonBindablePropertyType.ts, 28, 23), Decl(contextualComputedNonBindablePropertyType.ts, 28, 48)) +>propName : Symbol(propName, Decl(contextualComputedNonBindablePropertyType.ts, 28, 23), Decl(contextualComputedNonBindablePropertyType.ts, 28, 48)) + +const unexpectedlyFailingExample: Mapped = { +>unexpectedlyFailingExample : Symbol(unexpectedlyFailingExample, Decl(contextualComputedNonBindablePropertyType.ts, 30, 5)) +>Mapped : Symbol(Mapped, Decl(contextualComputedNonBindablePropertyType.ts, 22, 78)) + + foo: (arg) => 'expects a string literal', +>foo : Symbol(foo, Decl(contextualComputedNonBindablePropertyType.ts, 30, 44)) +>arg : Symbol(arg, Decl(contextualComputedNonBindablePropertyType.ts, 31, 8)) + + baz: (arg) => true, +>baz : Symbol(baz, Decl(contextualComputedNonBindablePropertyType.ts, 31, 43)) +>arg : Symbol(arg, Decl(contextualComputedNonBindablePropertyType.ts, 32, 8)) + + [propSelector('bar')]: (arg) => 51345 +>[propSelector('bar')] : Symbol([propSelector('bar')], Decl(contextualComputedNonBindablePropertyType.ts, 32, 21)) +>propSelector : Symbol(propSelector, Decl(contextualComputedNonBindablePropertyType.ts, 28, 5)) +>arg : Symbol(arg, Decl(contextualComputedNonBindablePropertyType.ts, 33, 26)) +} + diff --git a/tests/baselines/reference/contextualComputedNonBindablePropertyType.types b/tests/baselines/reference/contextualComputedNonBindablePropertyType.types new file mode 100644 index 00000000000..515c29b441d --- /dev/null +++ b/tests/baselines/reference/contextualComputedNonBindablePropertyType.types @@ -0,0 +1,97 @@ +=== tests/cases/compiler/contextualComputedNonBindablePropertyType.ts === +// repro #51906 + +declare function testD(): "d"; +>testD : () => "d" + +declare function forceMatch(matched: { +>forceMatch : (matched: { [key in keyof T]: key; }) => void +>matched : { [key in keyof T]: key; } + + [key in keyof T]: key; +}): void; + +forceMatch({ +>forceMatch({ [testD()]: "d",}) : void +>forceMatch : (matched: { [key in keyof T]: key; }) => void +>{ [testD()]: "d",} : { d: "d"; } + + [testD()]: "d", +>[testD()] : "d" +>testD() : "d" +>testD : () => "d" +>"d" : "d" + +}); + +declare function forceMatch2(matched: { +>forceMatch2 : (matched: { [key in keyof T]: ({ key }: { key: key; }) => void; }) => void +>matched : { [key in keyof T]: ({ key }: { key: key; }) => void; } + + [key in keyof T]: ({ key }: { key: key }) => void; +>key : key +>key : key + +}): void; + +forceMatch2({ +>forceMatch2({ [testD()]: ({ key }) => {},}) : void +>forceMatch2 : (matched: { [key in keyof T]: ({ key }: { key: key; }) => void; }) => void +>{ [testD()]: ({ key }) => {},} : { d: ({ key }: { key: "d"; }) => void; } + + [testD()]: ({ key }) => {}, +>[testD()] : ({ key }: { key: "d"; }) => void +>testD() : "d" +>testD : () => "d" +>({ key }) => {} : ({ key }: { key: "d"; }) => void +>key : "d" + +}); + +// repro #52954 + +type Original = { foo: 'expects a string literal', baz: boolean, bar: number } +>Original : { foo: 'expects a string literal'; baz: boolean; bar: number; } +>foo : "expects a string literal" +>baz : boolean +>bar : number + +type Mapped = { +>Mapped : { foo: (arg: "expects a string literal") => "expects a string literal"; baz: (arg: boolean) => boolean; bar: (arg: number) => number; } + + [prop in keyof Original]: (arg: Original[prop]) => Original[prop] +>arg : Original[prop] +} + +const propSelector = (propName: propName): propName => propName; +>propSelector : (propName: propName) => propName +>(propName: propName): propName => propName : (propName: propName) => propName +>propName : propName +>propName : propName + +const unexpectedlyFailingExample: Mapped = { +>unexpectedlyFailingExample : Mapped +>{ foo: (arg) => 'expects a string literal', baz: (arg) => true, [propSelector('bar')]: (arg) => 51345} : { foo: (arg: "expects a string literal") => "expects a string literal"; baz: (arg: boolean) => true; bar: (arg: number) => number; } + + foo: (arg) => 'expects a string literal', +>foo : (arg: "expects a string literal") => "expects a string literal" +>(arg) => 'expects a string literal' : (arg: "expects a string literal") => "expects a string literal" +>arg : "expects a string literal" +>'expects a string literal' : "expects a string literal" + + baz: (arg) => true, +>baz : (arg: boolean) => true +>(arg) => true : (arg: boolean) => true +>arg : boolean +>true : true + + [propSelector('bar')]: (arg) => 51345 +>[propSelector('bar')] : (arg: number) => number +>propSelector('bar') : "bar" +>propSelector : (propName: propName) => propName +>'bar' : "bar" +>(arg) => 51345 : (arg: number) => number +>arg : number +>51345 : 51345 +} + diff --git a/tests/cases/compiler/contextualComputedNonBindablePropertyType.ts b/tests/cases/compiler/contextualComputedNonBindablePropertyType.ts new file mode 100644 index 00000000000..0d7e73eb4ae --- /dev/null +++ b/tests/cases/compiler/contextualComputedNonBindablePropertyType.ts @@ -0,0 +1,38 @@ +// @noEmit: true +// @strict: true + +// repro #51906 + +declare function testD(): "d"; + +declare function forceMatch(matched: { + [key in keyof T]: key; +}): void; + +forceMatch({ + [testD()]: "d", +}); + +declare function forceMatch2(matched: { + [key in keyof T]: ({ key }: { key: key }) => void; +}): void; + +forceMatch2({ + [testD()]: ({ key }) => {}, +}); + +// repro #52954 + +type Original = { foo: 'expects a string literal', baz: boolean, bar: number } + +type Mapped = { + [prop in keyof Original]: (arg: Original[prop]) => Original[prop] +} + +const propSelector = (propName: propName): propName => propName; + +const unexpectedlyFailingExample: Mapped = { + foo: (arg) => 'expects a string literal', + baz: (arg) => true, + [propSelector('bar')]: (arg) => 51345 +}