Index signatures contribute properties to unions (#25307)
* Index signatures contribute properties to unions This means that in a union like this: ```ts type T = { foo: number } | { [s: string]: string } ``` `foo` is now a property of `T` with type `number | string`. Previously it was not. Two points of interest: 1. A readonly index signature makes the resulting union property readonly. 2. A numeric index signature only contributes number-named properties. Fixes #21141 * Correctly handle numeric and symbol property names 1. Symbol-named properties don't contribute to unions. 2. Number-named properties should use the numeric index signature type, if present, and fall back to the string index signature type, not the other way round.
This commit is contained in:
parent
fd007e747d
commit
c228924543
|
@ -5904,6 +5904,12 @@ namespace ts {
|
||||||
&& isTypeUsableAsLateBoundName(checkComputedPropertyName(node));
|
&& isTypeUsableAsLateBoundName(checkComputedPropertyName(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isLateBoundName(name: __String): boolean {
|
||||||
|
return (name as string).charCodeAt(0) === CharacterCodes._ &&
|
||||||
|
(name as string).charCodeAt(1) === CharacterCodes._ &&
|
||||||
|
(name as string).charCodeAt(2) === CharacterCodes.at;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether a declaration has a late-bindable dynamic name.
|
* Indicates whether a declaration has a late-bindable dynamic name.
|
||||||
*/
|
*/
|
||||||
|
@ -7010,6 +7016,7 @@ namespace ts {
|
||||||
|
|
||||||
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String): Symbol | undefined {
|
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String): Symbol | undefined {
|
||||||
let props: Symbol[] | undefined;
|
let props: Symbol[] | undefined;
|
||||||
|
let indexTypes: Type[] | undefined;
|
||||||
const isUnion = containingType.flags & TypeFlags.Union;
|
const isUnion = containingType.flags & TypeFlags.Union;
|
||||||
const excludeModifiers = isUnion ? ModifierFlags.NonPublicAccessibilityModifier : 0;
|
const excludeModifiers = isUnion ? ModifierFlags.NonPublicAccessibilityModifier : 0;
|
||||||
// Flags we want to propagate to the result if they exist in all source symbols
|
// Flags we want to propagate to the result if they exist in all source symbols
|
||||||
|
@ -7034,14 +7041,21 @@ namespace ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isUnion) {
|
else if (isUnion) {
|
||||||
|
const index = !isLateBoundName(name) && ((isNumericLiteralName(name) && getIndexInfoOfType(type, IndexKind.Number)) || getIndexInfoOfType(type, IndexKind.String));
|
||||||
|
if (index) {
|
||||||
|
checkFlags |= index.isReadonly ? CheckFlags.Readonly : 0;
|
||||||
|
indexTypes = append(indexTypes, index.type);
|
||||||
|
}
|
||||||
|
else {
|
||||||
checkFlags |= CheckFlags.Partial;
|
checkFlags |= CheckFlags.Partial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!props) {
|
if (!props) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (props.length === 1 && !(checkFlags & CheckFlags.Partial)) {
|
if (props.length === 1 && !(checkFlags & CheckFlags.Partial) && !indexTypes) {
|
||||||
return props[0];
|
return props[0];
|
||||||
}
|
}
|
||||||
let declarations: Declaration[] | undefined;
|
let declarations: Declaration[] | undefined;
|
||||||
|
@ -7072,6 +7086,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
propTypes.push(type);
|
propTypes.push(type);
|
||||||
}
|
}
|
||||||
|
addRange(propTypes, indexTypes);
|
||||||
const result = createSymbol(SymbolFlags.Property | commonFlags, name, syntheticFlag | checkFlags);
|
const result = createSymbol(SymbolFlags.Property | commonFlags, name, syntheticFlag | checkFlags);
|
||||||
result.containingType = containingType;
|
result.containingType = containingType;
|
||||||
if (!hasNonUniformValueDeclaration && commonValueDeclaration) {
|
if (!hasNonUniformValueDeclaration && commonValueDeclaration) {
|
||||||
|
|
|
@ -14,7 +14,9 @@ var bb;
|
||||||
|
|
||||||
var bbb = new mod.Baz();
|
var bbb = new mod.Baz();
|
||||||
>bbb : Symbol(bbb, Decl(use.js, 5, 3))
|
>bbb : Symbol(bbb, Decl(use.js, 5, 3))
|
||||||
|
>mod.Baz : Symbol(Baz)
|
||||||
>mod : Symbol(mod, Decl(use.js, 0, 3))
|
>mod : Symbol(mod, Decl(use.js, 0, 3))
|
||||||
|
>Baz : Symbol(Baz)
|
||||||
|
|
||||||
=== tests/cases/conformance/jsdoc/mod1.js ===
|
=== tests/cases/conformance/jsdoc/mod1.js ===
|
||||||
// error
|
// error
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(11,3): error TS2339: Property 'bar' does not exist on type 'Missing'.
|
||||||
|
Property 'bar' does not exist on type '{ [s: string]: string; }'.
|
||||||
|
tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(14,4): error TS2540: Cannot assign to 'foo' because it is a constant or a read-only property.
|
||||||
|
tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(24,1): error TS7017: Element implicitly has an 'any' type because type 'Both' has no index signature.
|
||||||
|
tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(25,1): error TS2322: Type '"not ok"' is not assignable to type 'number'.
|
||||||
|
tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(26,1): error TS7017: Element implicitly has an 'any' type because type 'Both' has no index signature.
|
||||||
|
|
||||||
|
|
||||||
|
==== tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts (5 errors) ====
|
||||||
|
type Two = { foo: { bar: true }, baz: true } | { [s: string]: string };
|
||||||
|
declare var u: Two
|
||||||
|
u.foo = 'bye'
|
||||||
|
u.baz = 'hi'
|
||||||
|
type Three = { foo: number } | { [s: string]: string } | { [s: string]: boolean };
|
||||||
|
declare var v: Three
|
||||||
|
v.foo = false
|
||||||
|
type Missing = { foo: number, bar: true } | { [s: string]: string } | { foo: boolean }
|
||||||
|
declare var m: Missing
|
||||||
|
m.foo = 'hi'
|
||||||
|
m.bar
|
||||||
|
~~~
|
||||||
|
!!! error TS2339: Property 'bar' does not exist on type 'Missing'.
|
||||||
|
!!! error TS2339: Property 'bar' does not exist on type '{ [s: string]: string; }'.
|
||||||
|
type RO = { foo: number } | { readonly [s: string]: string }
|
||||||
|
declare var ro: RO
|
||||||
|
ro.foo = 'not allowed'
|
||||||
|
~~~
|
||||||
|
!!! error TS2540: Cannot assign to 'foo' because it is a constant or a read-only property.
|
||||||
|
type Num = { '0': string } | { [n: number]: number }
|
||||||
|
declare var num: Num
|
||||||
|
num[0] = 1
|
||||||
|
num['0'] = 'ok'
|
||||||
|
const sym = Symbol()
|
||||||
|
type Both = { s: number, '0': number, [sym]: boolean } | { [n: number]: number, [s: string]: string | number }
|
||||||
|
declare var both: Both
|
||||||
|
both['s'] = 'ok'
|
||||||
|
both[0] = 1
|
||||||
|
both[1] = 0 // not ok
|
||||||
|
~~~~~~~
|
||||||
|
!!! error TS7017: Element implicitly has an 'any' type because type 'Both' has no index signature.
|
||||||
|
both[0] = 'not ok'
|
||||||
|
~~~~~~~
|
||||||
|
!!! error TS2322: Type '"not ok"' is not assignable to type 'number'.
|
||||||
|
both[sym] = 'not ok'
|
||||||
|
~~~~~~~~~
|
||||||
|
!!! error TS7017: Element implicitly has an 'any' type because type 'Both' has no index signature.
|
||||||
|
|
45
tests/baselines/reference/unionTypeWithIndexSignature.js
Normal file
45
tests/baselines/reference/unionTypeWithIndexSignature.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
//// [unionTypeWithIndexSignature.ts]
|
||||||
|
type Two = { foo: { bar: true }, baz: true } | { [s: string]: string };
|
||||||
|
declare var u: Two
|
||||||
|
u.foo = 'bye'
|
||||||
|
u.baz = 'hi'
|
||||||
|
type Three = { foo: number } | { [s: string]: string } | { [s: string]: boolean };
|
||||||
|
declare var v: Three
|
||||||
|
v.foo = false
|
||||||
|
type Missing = { foo: number, bar: true } | { [s: string]: string } | { foo: boolean }
|
||||||
|
declare var m: Missing
|
||||||
|
m.foo = 'hi'
|
||||||
|
m.bar
|
||||||
|
type RO = { foo: number } | { readonly [s: string]: string }
|
||||||
|
declare var ro: RO
|
||||||
|
ro.foo = 'not allowed'
|
||||||
|
type Num = { '0': string } | { [n: number]: number }
|
||||||
|
declare var num: Num
|
||||||
|
num[0] = 1
|
||||||
|
num['0'] = 'ok'
|
||||||
|
const sym = Symbol()
|
||||||
|
type Both = { s: number, '0': number, [sym]: boolean } | { [n: number]: number, [s: string]: string | number }
|
||||||
|
declare var both: Both
|
||||||
|
both['s'] = 'ok'
|
||||||
|
both[0] = 1
|
||||||
|
both[1] = 0 // not ok
|
||||||
|
both[0] = 'not ok'
|
||||||
|
both[sym] = 'not ok'
|
||||||
|
|
||||||
|
|
||||||
|
//// [unionTypeWithIndexSignature.js]
|
||||||
|
"use strict";
|
||||||
|
u.foo = 'bye';
|
||||||
|
u.baz = 'hi';
|
||||||
|
v.foo = false;
|
||||||
|
m.foo = 'hi';
|
||||||
|
m.bar;
|
||||||
|
ro.foo = 'not allowed';
|
||||||
|
num[0] = 1;
|
||||||
|
num['0'] = 'ok';
|
||||||
|
const sym = Symbol();
|
||||||
|
both['s'] = 'ok';
|
||||||
|
both[0] = 1;
|
||||||
|
both[1] = 0; // not ok
|
||||||
|
both[0] = 'not ok';
|
||||||
|
both[sym] = 'not ok';
|
123
tests/baselines/reference/unionTypeWithIndexSignature.symbols
Normal file
123
tests/baselines/reference/unionTypeWithIndexSignature.symbols
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
=== tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts ===
|
||||||
|
type Two = { foo: { bar: true }, baz: true } | { [s: string]: string };
|
||||||
|
>Two : Symbol(Two, Decl(unionTypeWithIndexSignature.ts, 0, 0))
|
||||||
|
>foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 0, 12))
|
||||||
|
>bar : Symbol(bar, Decl(unionTypeWithIndexSignature.ts, 0, 19))
|
||||||
|
>baz : Symbol(baz, Decl(unionTypeWithIndexSignature.ts, 0, 32))
|
||||||
|
>s : Symbol(s, Decl(unionTypeWithIndexSignature.ts, 0, 50))
|
||||||
|
|
||||||
|
declare var u: Two
|
||||||
|
>u : Symbol(u, Decl(unionTypeWithIndexSignature.ts, 1, 11))
|
||||||
|
>Two : Symbol(Two, Decl(unionTypeWithIndexSignature.ts, 0, 0))
|
||||||
|
|
||||||
|
u.foo = 'bye'
|
||||||
|
>u.foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 0, 12))
|
||||||
|
>u : Symbol(u, Decl(unionTypeWithIndexSignature.ts, 1, 11))
|
||||||
|
>foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 0, 12))
|
||||||
|
|
||||||
|
u.baz = 'hi'
|
||||||
|
>u.baz : Symbol(baz, Decl(unionTypeWithIndexSignature.ts, 0, 32))
|
||||||
|
>u : Symbol(u, Decl(unionTypeWithIndexSignature.ts, 1, 11))
|
||||||
|
>baz : Symbol(baz, Decl(unionTypeWithIndexSignature.ts, 0, 32))
|
||||||
|
|
||||||
|
type Three = { foo: number } | { [s: string]: string } | { [s: string]: boolean };
|
||||||
|
>Three : Symbol(Three, Decl(unionTypeWithIndexSignature.ts, 3, 12))
|
||||||
|
>foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 4, 14))
|
||||||
|
>s : Symbol(s, Decl(unionTypeWithIndexSignature.ts, 4, 34))
|
||||||
|
>s : Symbol(s, Decl(unionTypeWithIndexSignature.ts, 4, 60))
|
||||||
|
|
||||||
|
declare var v: Three
|
||||||
|
>v : Symbol(v, Decl(unionTypeWithIndexSignature.ts, 5, 11))
|
||||||
|
>Three : Symbol(Three, Decl(unionTypeWithIndexSignature.ts, 3, 12))
|
||||||
|
|
||||||
|
v.foo = false
|
||||||
|
>v.foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 4, 14))
|
||||||
|
>v : Symbol(v, Decl(unionTypeWithIndexSignature.ts, 5, 11))
|
||||||
|
>foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 4, 14))
|
||||||
|
|
||||||
|
type Missing = { foo: number, bar: true } | { [s: string]: string } | { foo: boolean }
|
||||||
|
>Missing : Symbol(Missing, Decl(unionTypeWithIndexSignature.ts, 6, 13))
|
||||||
|
>foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 7, 16))
|
||||||
|
>bar : Symbol(bar, Decl(unionTypeWithIndexSignature.ts, 7, 29))
|
||||||
|
>s : Symbol(s, Decl(unionTypeWithIndexSignature.ts, 7, 47))
|
||||||
|
>foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 7, 71))
|
||||||
|
|
||||||
|
declare var m: Missing
|
||||||
|
>m : Symbol(m, Decl(unionTypeWithIndexSignature.ts, 8, 11))
|
||||||
|
>Missing : Symbol(Missing, Decl(unionTypeWithIndexSignature.ts, 6, 13))
|
||||||
|
|
||||||
|
m.foo = 'hi'
|
||||||
|
>m.foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 7, 16), Decl(unionTypeWithIndexSignature.ts, 7, 71))
|
||||||
|
>m : Symbol(m, Decl(unionTypeWithIndexSignature.ts, 8, 11))
|
||||||
|
>foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 7, 16), Decl(unionTypeWithIndexSignature.ts, 7, 71))
|
||||||
|
|
||||||
|
m.bar
|
||||||
|
>m : Symbol(m, Decl(unionTypeWithIndexSignature.ts, 8, 11))
|
||||||
|
|
||||||
|
type RO = { foo: number } | { readonly [s: string]: string }
|
||||||
|
>RO : Symbol(RO, Decl(unionTypeWithIndexSignature.ts, 10, 5))
|
||||||
|
>foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 11, 11))
|
||||||
|
>s : Symbol(s, Decl(unionTypeWithIndexSignature.ts, 11, 40))
|
||||||
|
|
||||||
|
declare var ro: RO
|
||||||
|
>ro : Symbol(ro, Decl(unionTypeWithIndexSignature.ts, 12, 11))
|
||||||
|
>RO : Symbol(RO, Decl(unionTypeWithIndexSignature.ts, 10, 5))
|
||||||
|
|
||||||
|
ro.foo = 'not allowed'
|
||||||
|
>ro.foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 11, 11))
|
||||||
|
>ro : Symbol(ro, Decl(unionTypeWithIndexSignature.ts, 12, 11))
|
||||||
|
>foo : Symbol(foo, Decl(unionTypeWithIndexSignature.ts, 11, 11))
|
||||||
|
|
||||||
|
type Num = { '0': string } | { [n: number]: number }
|
||||||
|
>Num : Symbol(Num, Decl(unionTypeWithIndexSignature.ts, 13, 22))
|
||||||
|
>'0' : Symbol('0', Decl(unionTypeWithIndexSignature.ts, 14, 12))
|
||||||
|
>n : Symbol(n, Decl(unionTypeWithIndexSignature.ts, 14, 32))
|
||||||
|
|
||||||
|
declare var num: Num
|
||||||
|
>num : Symbol(num, Decl(unionTypeWithIndexSignature.ts, 15, 11))
|
||||||
|
>Num : Symbol(Num, Decl(unionTypeWithIndexSignature.ts, 13, 22))
|
||||||
|
|
||||||
|
num[0] = 1
|
||||||
|
>num : Symbol(num, Decl(unionTypeWithIndexSignature.ts, 15, 11))
|
||||||
|
>0 : Symbol('0', Decl(unionTypeWithIndexSignature.ts, 14, 12))
|
||||||
|
|
||||||
|
num['0'] = 'ok'
|
||||||
|
>num : Symbol(num, Decl(unionTypeWithIndexSignature.ts, 15, 11))
|
||||||
|
>'0' : Symbol('0', Decl(unionTypeWithIndexSignature.ts, 14, 12))
|
||||||
|
|
||||||
|
const sym = Symbol()
|
||||||
|
>sym : Symbol(sym, Decl(unionTypeWithIndexSignature.ts, 18, 5))
|
||||||
|
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.symbol.d.ts, --, --))
|
||||||
|
|
||||||
|
type Both = { s: number, '0': number, [sym]: boolean } | { [n: number]: number, [s: string]: string | number }
|
||||||
|
>Both : Symbol(Both, Decl(unionTypeWithIndexSignature.ts, 18, 20))
|
||||||
|
>s : Symbol(s, Decl(unionTypeWithIndexSignature.ts, 19, 13))
|
||||||
|
>'0' : Symbol('0', Decl(unionTypeWithIndexSignature.ts, 19, 24))
|
||||||
|
>[sym] : Symbol([sym], Decl(unionTypeWithIndexSignature.ts, 19, 37))
|
||||||
|
>sym : Symbol(sym, Decl(unionTypeWithIndexSignature.ts, 18, 5))
|
||||||
|
>n : Symbol(n, Decl(unionTypeWithIndexSignature.ts, 19, 60))
|
||||||
|
>s : Symbol(s, Decl(unionTypeWithIndexSignature.ts, 19, 81))
|
||||||
|
|
||||||
|
declare var both: Both
|
||||||
|
>both : Symbol(both, Decl(unionTypeWithIndexSignature.ts, 20, 11))
|
||||||
|
>Both : Symbol(Both, Decl(unionTypeWithIndexSignature.ts, 18, 20))
|
||||||
|
|
||||||
|
both['s'] = 'ok'
|
||||||
|
>both : Symbol(both, Decl(unionTypeWithIndexSignature.ts, 20, 11))
|
||||||
|
>'s' : Symbol(s, Decl(unionTypeWithIndexSignature.ts, 19, 13))
|
||||||
|
|
||||||
|
both[0] = 1
|
||||||
|
>both : Symbol(both, Decl(unionTypeWithIndexSignature.ts, 20, 11))
|
||||||
|
>0 : Symbol('0', Decl(unionTypeWithIndexSignature.ts, 19, 24))
|
||||||
|
|
||||||
|
both[1] = 0 // not ok
|
||||||
|
>both : Symbol(both, Decl(unionTypeWithIndexSignature.ts, 20, 11))
|
||||||
|
|
||||||
|
both[0] = 'not ok'
|
||||||
|
>both : Symbol(both, Decl(unionTypeWithIndexSignature.ts, 20, 11))
|
||||||
|
>0 : Symbol('0', Decl(unionTypeWithIndexSignature.ts, 19, 24))
|
||||||
|
|
||||||
|
both[sym] = 'not ok'
|
||||||
|
>both : Symbol(both, Decl(unionTypeWithIndexSignature.ts, 20, 11))
|
||||||
|
>sym : Symbol(sym, Decl(unionTypeWithIndexSignature.ts, 18, 5))
|
||||||
|
|
161
tests/baselines/reference/unionTypeWithIndexSignature.types
Normal file
161
tests/baselines/reference/unionTypeWithIndexSignature.types
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
=== tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts ===
|
||||||
|
type Two = { foo: { bar: true }, baz: true } | { [s: string]: string };
|
||||||
|
>Two : Two
|
||||||
|
>foo : { bar: true; }
|
||||||
|
>bar : true
|
||||||
|
>true : true
|
||||||
|
>baz : true
|
||||||
|
>true : true
|
||||||
|
>s : string
|
||||||
|
|
||||||
|
declare var u: Two
|
||||||
|
>u : Two
|
||||||
|
>Two : Two
|
||||||
|
|
||||||
|
u.foo = 'bye'
|
||||||
|
>u.foo = 'bye' : "bye"
|
||||||
|
>u.foo : string | { bar: true; }
|
||||||
|
>u : Two
|
||||||
|
>foo : string | { bar: true; }
|
||||||
|
>'bye' : "bye"
|
||||||
|
|
||||||
|
u.baz = 'hi'
|
||||||
|
>u.baz = 'hi' : "hi"
|
||||||
|
>u.baz : string | true
|
||||||
|
>u : Two
|
||||||
|
>baz : string | true
|
||||||
|
>'hi' : "hi"
|
||||||
|
|
||||||
|
type Three = { foo: number } | { [s: string]: string } | { [s: string]: boolean };
|
||||||
|
>Three : Three
|
||||||
|
>foo : number
|
||||||
|
>s : string
|
||||||
|
>s : string
|
||||||
|
|
||||||
|
declare var v: Three
|
||||||
|
>v : Three
|
||||||
|
>Three : Three
|
||||||
|
|
||||||
|
v.foo = false
|
||||||
|
>v.foo = false : false
|
||||||
|
>v.foo : string | number | boolean
|
||||||
|
>v : Three
|
||||||
|
>foo : string | number | boolean
|
||||||
|
>false : false
|
||||||
|
|
||||||
|
type Missing = { foo: number, bar: true } | { [s: string]: string } | { foo: boolean }
|
||||||
|
>Missing : Missing
|
||||||
|
>foo : number
|
||||||
|
>bar : true
|
||||||
|
>true : true
|
||||||
|
>s : string
|
||||||
|
>foo : boolean
|
||||||
|
|
||||||
|
declare var m: Missing
|
||||||
|
>m : Missing
|
||||||
|
>Missing : Missing
|
||||||
|
|
||||||
|
m.foo = 'hi'
|
||||||
|
>m.foo = 'hi' : "hi"
|
||||||
|
>m.foo : string | number | boolean
|
||||||
|
>m : Missing
|
||||||
|
>foo : string | number | boolean
|
||||||
|
>'hi' : "hi"
|
||||||
|
|
||||||
|
m.bar
|
||||||
|
>m.bar : any
|
||||||
|
>m : Missing
|
||||||
|
>bar : any
|
||||||
|
|
||||||
|
type RO = { foo: number } | { readonly [s: string]: string }
|
||||||
|
>RO : RO
|
||||||
|
>foo : number
|
||||||
|
>s : string
|
||||||
|
|
||||||
|
declare var ro: RO
|
||||||
|
>ro : RO
|
||||||
|
>RO : RO
|
||||||
|
|
||||||
|
ro.foo = 'not allowed'
|
||||||
|
>ro.foo = 'not allowed' : "not allowed"
|
||||||
|
>ro.foo : any
|
||||||
|
>ro : RO
|
||||||
|
>foo : any
|
||||||
|
>'not allowed' : "not allowed"
|
||||||
|
|
||||||
|
type Num = { '0': string } | { [n: number]: number }
|
||||||
|
>Num : Num
|
||||||
|
>'0' : string
|
||||||
|
>n : number
|
||||||
|
|
||||||
|
declare var num: Num
|
||||||
|
>num : Num
|
||||||
|
>Num : Num
|
||||||
|
|
||||||
|
num[0] = 1
|
||||||
|
>num[0] = 1 : 1
|
||||||
|
>num[0] : string | number
|
||||||
|
>num : Num
|
||||||
|
>0 : 0
|
||||||
|
>1 : 1
|
||||||
|
|
||||||
|
num['0'] = 'ok'
|
||||||
|
>num['0'] = 'ok' : "ok"
|
||||||
|
>num['0'] : string | number
|
||||||
|
>num : Num
|
||||||
|
>'0' : "0"
|
||||||
|
>'ok' : "ok"
|
||||||
|
|
||||||
|
const sym = Symbol()
|
||||||
|
>sym : unique symbol
|
||||||
|
>Symbol() : unique symbol
|
||||||
|
>Symbol : SymbolConstructor
|
||||||
|
|
||||||
|
type Both = { s: number, '0': number, [sym]: boolean } | { [n: number]: number, [s: string]: string | number }
|
||||||
|
>Both : Both
|
||||||
|
>s : number
|
||||||
|
>'0' : number
|
||||||
|
>[sym] : boolean
|
||||||
|
>sym : unique symbol
|
||||||
|
>n : number
|
||||||
|
>s : string
|
||||||
|
|
||||||
|
declare var both: Both
|
||||||
|
>both : Both
|
||||||
|
>Both : Both
|
||||||
|
|
||||||
|
both['s'] = 'ok'
|
||||||
|
>both['s'] = 'ok' : "ok"
|
||||||
|
>both['s'] : string | number
|
||||||
|
>both : Both
|
||||||
|
>'s' : "s"
|
||||||
|
>'ok' : "ok"
|
||||||
|
|
||||||
|
both[0] = 1
|
||||||
|
>both[0] = 1 : 1
|
||||||
|
>both[0] : number
|
||||||
|
>both : Both
|
||||||
|
>0 : 0
|
||||||
|
>1 : 1
|
||||||
|
|
||||||
|
both[1] = 0 // not ok
|
||||||
|
>both[1] = 0 : 0
|
||||||
|
>both[1] : any
|
||||||
|
>both : Both
|
||||||
|
>1 : 1
|
||||||
|
>0 : 0
|
||||||
|
|
||||||
|
both[0] = 'not ok'
|
||||||
|
>both[0] = 'not ok' : "not ok"
|
||||||
|
>both[0] : number
|
||||||
|
>both : Both
|
||||||
|
>0 : 0
|
||||||
|
>'not ok' : "not ok"
|
||||||
|
|
||||||
|
both[sym] = 'not ok'
|
||||||
|
>both[sym] = 'not ok' : "not ok"
|
||||||
|
>both[sym] : any
|
||||||
|
>both : Both
|
||||||
|
>sym : unique symbol
|
||||||
|
>'not ok' : "not ok"
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
// @target: esnext
|
||||||
|
// @strict: true
|
||||||
|
type Two = { foo: { bar: true }, baz: true } | { [s: string]: string };
|
||||||
|
declare var u: Two
|
||||||
|
u.foo = 'bye'
|
||||||
|
u.baz = 'hi'
|
||||||
|
type Three = { foo: number } | { [s: string]: string } | { [s: string]: boolean };
|
||||||
|
declare var v: Three
|
||||||
|
v.foo = false
|
||||||
|
type Missing = { foo: number, bar: true } | { [s: string]: string } | { foo: boolean }
|
||||||
|
declare var m: Missing
|
||||||
|
m.foo = 'hi'
|
||||||
|
m.bar
|
||||||
|
type RO = { foo: number } | { readonly [s: string]: string }
|
||||||
|
declare var ro: RO
|
||||||
|
ro.foo = 'not allowed'
|
||||||
|
type Num = { '0': string } | { [n: number]: number }
|
||||||
|
declare var num: Num
|
||||||
|
num[0] = 1
|
||||||
|
num['0'] = 'ok'
|
||||||
|
const sym = Symbol()
|
||||||
|
type Both = { s: number, '0': number, [sym]: boolean } | { [n: number]: number, [s: string]: string | number }
|
||||||
|
declare var both: Both
|
||||||
|
both['s'] = 'ok'
|
||||||
|
both[0] = 1
|
||||||
|
both[1] = 0 // not ok
|
||||||
|
both[0] = 'not ok'
|
||||||
|
both[sym] = 'not ok'
|
Loading…
Reference in a new issue