Computed property names are const contexts
By analogy with the existing rule that element access argument expressions are a const context. Fixes #45798
This commit is contained in:
parent
0d022130be
commit
b93892a6f3
|
@ -33488,6 +33488,7 @@ namespace ts {
|
|||
const parent = node.parent;
|
||||
return isAssertionExpression(parent) && isConstTypeReference(parent.type) ||
|
||||
isJSDocTypeAssertion(parent) && isConstTypeReference(getJSDocTypeAssertionType(parent)) ||
|
||||
isComputedPropertyName(parent) ||
|
||||
(isParenthesizedExpression(parent) || isArrayLiteralExpression(parent) || isSpreadElement(parent)) && isConstContext(parent) ||
|
||||
(isPropertyAssignment(parent) || isShorthandPropertyAssignment(parent) || isTemplateSpan(parent)) && isConstContext(parent.parent);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
tests/cases/conformance/expressions/literals/constContextTemplateLiteral.ts(10,24): error TS2418: Type of computed property's value is '{ b: string; }', which is not assignable to type '{ a: any; }'.
|
||||
Object literal may only specify known properties, and 'b' does not exist in type '{ a: any; }'.
|
||||
tests/cases/conformance/expressions/literals/constContextTemplateLiteral.ts(11,33): error TS2418: Type of computed property's value is '{ b: string; }', which is not assignable to type '{ a: any; }'.
|
||||
Object literal may only specify known properties, and 'b' does not exist in type '{ a: any; }'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/expressions/literals/constContextTemplateLiteral.ts (2 errors) ====
|
||||
interface Person {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
declare function key(): `person-${number}`
|
||||
/* This only happens if index type is a template literal type */
|
||||
const persons: Record<`person-${Person["id"]}`, { a: any }> = {
|
||||
...{},
|
||||
[`person-${1}`]: { b: "something" }, // ok, error
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2418: Type of computed property's value is '{ b: string; }', which is not assignable to type '{ a: any; }'.
|
||||
!!! error TS2418: Object literal may only specify known properties, and 'b' does not exist in type '{ a: any; }'.
|
||||
[`person-${1}` as const]: { b: "something" }, // ok, error
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2418: Type of computed property's value is '{ b: string; }', which is not assignable to type '{ a: any; }'.
|
||||
!!! error TS2418: Object literal may only specify known properties, and 'b' does not exist in type '{ a: any; }'.
|
||||
[key()]: { b: "something" }, // still no error
|
||||
}
|
||||
|
31
tests/baselines/reference/constContextTemplateLiteral.js
Normal file
31
tests/baselines/reference/constContextTemplateLiteral.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
//// [constContextTemplateLiteral.ts]
|
||||
interface Person {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
declare function key(): `person-${number}`
|
||||
/* This only happens if index type is a template literal type */
|
||||
const persons: Record<`person-${Person["id"]}`, { a: any }> = {
|
||||
...{},
|
||||
[`person-${1}`]: { b: "something" }, // ok, error
|
||||
[`person-${1}` as const]: { b: "something" }, // ok, error
|
||||
[key()]: { b: "something" }, // still no error
|
||||
}
|
||||
|
||||
|
||||
//// [constContextTemplateLiteral.js]
|
||||
var __assign = (this && this.__assign) || function () {
|
||||
__assign = Object.assign || function(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||
t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
var _a;
|
||||
/* This only happens if index type is a template literal type */
|
||||
var persons = __assign({}, (_a = {}, _a["person-".concat(1)] = { b: "something" }, _a["person-".concat(1)] = { b: "something" }, _a[key()] = { b: "something" }, _a));
|
|
@ -0,0 +1,37 @@
|
|||
=== tests/cases/conformance/expressions/literals/constContextTemplateLiteral.ts ===
|
||||
interface Person {
|
||||
>Person : Symbol(Person, Decl(constContextTemplateLiteral.ts, 0, 0))
|
||||
|
||||
id: number;
|
||||
>id : Symbol(Person.id, Decl(constContextTemplateLiteral.ts, 0, 18))
|
||||
|
||||
name: string;
|
||||
>name : Symbol(Person.name, Decl(constContextTemplateLiteral.ts, 1, 15))
|
||||
}
|
||||
|
||||
declare function key(): `person-${number}`
|
||||
>key : Symbol(key, Decl(constContextTemplateLiteral.ts, 3, 1))
|
||||
|
||||
/* This only happens if index type is a template literal type */
|
||||
const persons: Record<`person-${Person["id"]}`, { a: any }> = {
|
||||
>persons : Symbol(persons, Decl(constContextTemplateLiteral.ts, 7, 5))
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
>Person : Symbol(Person, Decl(constContextTemplateLiteral.ts, 0, 0))
|
||||
>a : Symbol(a, Decl(constContextTemplateLiteral.ts, 7, 49))
|
||||
|
||||
...{},
|
||||
[`person-${1}`]: { b: "something" }, // ok, error
|
||||
>[`person-${1}`] : Symbol([`person-${1}`], Decl(constContextTemplateLiteral.ts, 8, 10))
|
||||
>b : Symbol(b, Decl(constContextTemplateLiteral.ts, 9, 22))
|
||||
|
||||
[`person-${1}` as const]: { b: "something" }, // ok, error
|
||||
>[`person-${1}` as const] : Symbol([`person-${1}` as const], Decl(constContextTemplateLiteral.ts, 9, 40))
|
||||
>const : Symbol(const)
|
||||
>b : Symbol(b, Decl(constContextTemplateLiteral.ts, 10, 31))
|
||||
|
||||
[key()]: { b: "something" }, // still no error
|
||||
>[key()] : Symbol([key()], Decl(constContextTemplateLiteral.ts, 10, 49))
|
||||
>key : Symbol(key, Decl(constContextTemplateLiteral.ts, 3, 1))
|
||||
>b : Symbol(b, Decl(constContextTemplateLiteral.ts, 11, 14))
|
||||
}
|
||||
|
47
tests/baselines/reference/constContextTemplateLiteral.types
Normal file
47
tests/baselines/reference/constContextTemplateLiteral.types
Normal file
|
@ -0,0 +1,47 @@
|
|||
=== tests/cases/conformance/expressions/literals/constContextTemplateLiteral.ts ===
|
||||
interface Person {
|
||||
id: number;
|
||||
>id : number
|
||||
|
||||
name: string;
|
||||
>name : string
|
||||
}
|
||||
|
||||
declare function key(): `person-${number}`
|
||||
>key : () => `person-${number}`
|
||||
|
||||
/* This only happens if index type is a template literal type */
|
||||
const persons: Record<`person-${Person["id"]}`, { a: any }> = {
|
||||
>persons : Record<`person-${number}`, { a: any; }>
|
||||
>a : any
|
||||
>{ ...{}, [`person-${1}`]: { b: "something" }, // ok, error [`person-${1}` as const]: { b: "something" }, // ok, error [key()]: { b: "something" }, // still no error} : { "person-1": { b: string; }; }
|
||||
|
||||
...{},
|
||||
>{} : {}
|
||||
|
||||
[`person-${1}`]: { b: "something" }, // ok, error
|
||||
>[`person-${1}`] : { b: string; }
|
||||
>`person-${1}` : "person-1"
|
||||
>1 : 1
|
||||
>{ b: "something" } : { b: string; }
|
||||
>b : string
|
||||
>"something" : "something"
|
||||
|
||||
[`person-${1}` as const]: { b: "something" }, // ok, error
|
||||
>[`person-${1}` as const] : { b: string; }
|
||||
>`person-${1}` as const : "person-1"
|
||||
>`person-${1}` : "person-1"
|
||||
>1 : 1
|
||||
>{ b: "something" } : { b: string; }
|
||||
>b : string
|
||||
>"something" : "something"
|
||||
|
||||
[key()]: { b: "something" }, // still no error
|
||||
>[key()] : { b: string; }
|
||||
>key() : `person-${number}`
|
||||
>key : () => `person-${number}`
|
||||
>{ b: "something" } : { b: string; }
|
||||
>b : string
|
||||
>"something" : "something"
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
interface Person {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
declare function key(): `person-${number}`
|
||||
/* This only happens if index type is a template literal type */
|
||||
const persons: Record<`person-${Person["id"]}`, { a: any }> = {
|
||||
...{},
|
||||
[`person-${1}`]: { b: "something" }, // ok, error
|
||||
[`person-${1}` as const]: { b: "something" }, // ok, error
|
||||
[key()]: { b: "something" }, // still no error
|
||||
}
|
Loading…
Reference in a new issue