Ensure singleton types always compare identical (#44565)

* Singleton types should compare identical + fix boolean types

* Add tests

* Accept new baselines
This commit is contained in:
Anders Hejlsberg 2021-06-13 12:51:36 -07:00 committed by GitHub
parent 4829a7fedd
commit 6a1623d413
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 598 additions and 36 deletions

View File

@ -757,12 +757,7 @@ namespace ts {
falseType.freshType = falseType;
regularFalseType.regularType = regularFalseType;
regularFalseType.freshType = falseType;
const booleanType = createBooleanType([regularFalseType, regularTrueType]);
// Also mark all combinations of fresh/regular booleans as "Boolean" so they print as `boolean` instead of `true | false`
// (The union is cached, so simply doing the marking here is sufficient)
createBooleanType([regularFalseType, trueType]);
createBooleanType([falseType, regularTrueType]);
createBooleanType([falseType, trueType]);
const booleanType = getUnionType([regularFalseType, regularTrueType]);
const esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol");
const voidType = createIntrinsicType(TypeFlags.Void, "void");
const neverType = createIntrinsicType(TypeFlags.Never, "never");
@ -3837,13 +3832,6 @@ namespace ts {
return type;
}
function createBooleanType(trueFalseTypes: readonly Type[]): IntrinsicType & UnionType {
const type = getUnionType(trueFalseTypes) as IntrinsicType & UnionType;
type.flags |= TypeFlags.Boolean;
type.intrinsicName = "boolean";
return type;
}
function createObjectType(objectFlags: ObjectFlags, symbol?: Symbol): ObjectType {
const type = createType(TypeFlags.Object) as ObjectType;
type.objectFlags = objectFlags;
@ -4584,7 +4572,7 @@ namespace ts {
context.approximateLength += 6;
return factory.createKeywordTypeNode(SyntaxKind.BigIntKeyword);
}
if (type.flags & TypeFlags.Boolean) {
if (type.flags & TypeFlags.Boolean && !type.aliasSymbol) {
context.approximateLength += 7;
return factory.createKeywordTypeNode(SyntaxKind.BooleanKeyword);
}
@ -13975,16 +13963,6 @@ namespace ts {
return a.kind === b.kind && a.parameterIndex === b.parameterIndex;
}
function createUnionType(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type) {
const result = createType(TypeFlags.Union) as UnionType;
result.objectFlags = getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
result.types = types;
result.origin = origin;
result.aliasSymbol = aliasSymbol;
result.aliasTypeArguments = aliasTypeArguments;
return result;
}
// This function assumes the constituent type list is sorted and deduplicated.
function getUnionTypeFromSortedList(types: Type[], objectFlags: ObjectFlags, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type): Type {
if (types.length === 0) {
@ -14000,8 +13978,16 @@ namespace ts {
const id = typeKey + getAliasId(aliasSymbol, aliasTypeArguments);
let type = unionTypes.get(id);
if (!type) {
type = createUnionType(types, aliasSymbol, aliasTypeArguments, origin);
type.objectFlags |= objectFlags;
type = createType(TypeFlags.Union) as UnionType;
type.objectFlags = objectFlags | getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
type.types = types;
type.origin = origin;
type.aliasSymbol = aliasSymbol;
type.aliasTypeArguments = aliasTypeArguments;
if (types.length === 2 && types[0].flags & TypeFlags.BooleanLiteral && types[1].flags & TypeFlags.BooleanLiteral) {
type.flags |= TypeFlags.Boolean;
(type as UnionType & IntrinsicType).intrinsicName = "boolean";
}
unionTypes.set(id, type);
}
return type;
@ -17329,8 +17315,8 @@ namespace ts {
}
}
else {
if (!(source.flags & TypeFlags.UnionOrIntersection) && !(target.flags & TypeFlags.UnionOrIntersection) &&
source.flags !== target.flags && !(source.flags & TypeFlags.Substructure)) return false;
if (source.flags !== target.flags) return false;
if (source.flags & TypeFlags.Singleton) return true;
}
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation));
@ -17932,12 +17918,10 @@ namespace ts {
}
function isIdenticalTo(source: Type, target: Type): Ternary {
const flags = source.flags & target.flags;
if (!(flags & TypeFlags.Substructure)) {
return Ternary.False;
}
if (source.flags !== target.flags) return Ternary.False;
if (source.flags & TypeFlags.Singleton) return Ternary.True;
traceUnionsOrIntersectionsTooLarge(source, target);
if (flags & TypeFlags.UnionOrIntersection) {
if (source.flags & TypeFlags.UnionOrIntersection) {
let result = eachTypeRelatedToSomeType(source as UnionOrIntersectionType, target as UnionOrIntersectionType);
if (result) {
result &= eachTypeRelatedToSomeType(target as UnionOrIntersectionType, source as UnionOrIntersectionType);
@ -21132,7 +21116,6 @@ namespace ts {
inferFromTypes(originalSource, originalTarget);
function inferFromTypes(source: Type, target: Type): void {
if (!couldContainTypeVariables(target)) {
return;
}
@ -21750,7 +21733,8 @@ namespace ts {
}
function isTypeOrBaseIdenticalTo(s: Type, t: Type) {
return isTypeIdenticalTo(s, t) || !!(t.flags & TypeFlags.String && s.flags & TypeFlags.StringLiteral || t.flags & TypeFlags.Number && s.flags & TypeFlags.NumberLiteral);
return strictOptionalProperties && t === missingType ? s === t :
(isTypeIdenticalTo(s, t) || !!(t.flags & TypeFlags.String && s.flags & TypeFlags.StringLiteral || t.flags & TypeFlags.Number && s.flags & TypeFlags.NumberLiteral));
}
function isTypeCloselyMatchedBy(s: Type, t: Type) {

View File

@ -5090,7 +5090,7 @@ namespace ts {
/* @internal */
Simplifiable = IndexedAccess | Conditional,
/* @internal */
Substructure = Object | Union | Intersection | Index | IndexedAccess | Conditional | Substitution | TemplateLiteral | StringMapping,
Singleton = Any | Unknown | String | Number | Boolean | BigInt | ESSymbol | Void | Undefined | Null | Never | NonPrimitive,
// 'Narrowable' types are types where narrowing actually narrows.
// This *should* be every type other than null, undefined, void, and never
Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive,

View File

@ -182,4 +182,64 @@ tests/cases/compiler/strictOptionalProperties1.ts(119,5): error TS2411: Property
~~~
!!! error TS2411: Property 'bar' of type 'string | undefined' is not assignable to string index type 'string'.
}
// Strict optional properties and inference
declare let ox1: { p: string };
declare let ox2: { p: string | undefined };
declare let ox3: { p?: string };
declare let ox4: { p?: string | undefined };
declare let tx1: [string];
declare let tx2: [string | undefined];
declare let tx3: [string?];
declare let tx4: [(string | undefined)?];
declare function f11<T>(x: { p?: T }): T;
f11(ox1); // string
f11(ox2); // string | undefined
f11(ox3); // string
f11(ox4); // string | undefined
declare function f12<T>(x: [T?]): T;
f12(tx1); // string
f12(tx2); // string | undefined
f12(tx3); // string
f12(tx4); // string | undefined
declare function f13<T>(x: Partial<T>): T;
f13(ox1); // { p: string }
f13(ox2); // { p: string | undefined }
f13(ox3); // { p: string }
f13(ox4); // { p: string | undefined }
f13(tx1); // [string]
f13(tx2); // [string | undefined]
f13(tx3); // [string]
f13(tx4); // [string | undefined]
// Repro from #44388
type Undefinable<T> = T | undefined;
function expectNotUndefined<T>(value: Undefinable<T>): T {
if (value === undefined) {
throw new TypeError('value is undefined');
}
return value;
}
interface Bar {
bar?: number;
}
function aa(input: Bar): void {
const notUndefinedVal = expectNotUndefined(input.bar);
bb(notUndefinedVal);
}
declare function bb(input: number): void;

View File

@ -119,6 +119,66 @@ interface Test {
foo?: string; // Should be ok
bar?: string | undefined; // Error
}
// Strict optional properties and inference
declare let ox1: { p: string };
declare let ox2: { p: string | undefined };
declare let ox3: { p?: string };
declare let ox4: { p?: string | undefined };
declare let tx1: [string];
declare let tx2: [string | undefined];
declare let tx3: [string?];
declare let tx4: [(string | undefined)?];
declare function f11<T>(x: { p?: T }): T;
f11(ox1); // string
f11(ox2); // string | undefined
f11(ox3); // string
f11(ox4); // string | undefined
declare function f12<T>(x: [T?]): T;
f12(tx1); // string
f12(tx2); // string | undefined
f12(tx3); // string
f12(tx4); // string | undefined
declare function f13<T>(x: Partial<T>): T;
f13(ox1); // { p: string }
f13(ox2); // { p: string | undefined }
f13(ox3); // { p: string }
f13(ox4); // { p: string | undefined }
f13(tx1); // [string]
f13(tx2); // [string | undefined]
f13(tx3); // [string]
f13(tx4); // [string | undefined]
// Repro from #44388
type Undefinable<T> = T | undefined;
function expectNotUndefined<T>(value: Undefinable<T>): T {
if (value === undefined) {
throw new TypeError('value is undefined');
}
return value;
}
interface Bar {
bar?: number;
}
function aa(input: Bar): void {
const notUndefinedVal = expectNotUndefined(input.bar);
bb(notUndefinedVal);
}
declare function bb(input: number): void;
//// [strictOptionalProperties1.js]
@ -223,6 +283,32 @@ var t4 = [1, undefined, undefined];
// Example from #13195
var x = { foo: undefined };
var y = __assign({ foo: 123 }, x);
f11(ox1); // string
f11(ox2); // string | undefined
f11(ox3); // string
f11(ox4); // string | undefined
f12(tx1); // string
f12(tx2); // string | undefined
f12(tx3); // string
f12(tx4); // string | undefined
f13(ox1); // { p: string }
f13(ox2); // { p: string | undefined }
f13(ox3); // { p: string }
f13(ox4); // { p: string | undefined }
f13(tx1); // [string]
f13(tx2); // [string | undefined]
f13(tx3); // [string]
f13(tx4); // [string | undefined]
function expectNotUndefined(value) {
if (value === undefined) {
throw new TypeError('value is undefined');
}
return value;
}
function aa(input) {
var notUndefinedVal = expectNotUndefined(input.bar);
bb(notUndefinedVal);
}
//// [strictOptionalProperties1.d.ts]
@ -268,3 +354,31 @@ interface Test {
foo?: string;
bar?: string | undefined;
}
declare let ox1: {
p: string;
};
declare let ox2: {
p: string | undefined;
};
declare let ox3: {
p?: string;
};
declare let ox4: {
p?: string | undefined;
};
declare let tx1: [string];
declare let tx2: [string | undefined];
declare let tx3: [string?];
declare let tx4: [(string | undefined)?];
declare function f11<T>(x: {
p?: T;
}): T;
declare function f12<T>(x: [T?]): T;
declare function f13<T>(x: Partial<T>): T;
declare type Undefinable<T> = T | undefined;
declare function expectNotUndefined<T>(value: Undefinable<T>): T;
interface Bar {
bar?: number;
}
declare function aa(input: Bar): void;
declare function bb(input: number): void;

View File

@ -400,3 +400,174 @@ interface Test {
>bar : Symbol(Test.bar, Decl(strictOptionalProperties1.ts, 117, 17))
}
// Strict optional properties and inference
declare let ox1: { p: string };
>ox1 : Symbol(ox1, Decl(strictOptionalProperties1.ts, 123, 11))
>p : Symbol(p, Decl(strictOptionalProperties1.ts, 123, 18))
declare let ox2: { p: string | undefined };
>ox2 : Symbol(ox2, Decl(strictOptionalProperties1.ts, 124, 11))
>p : Symbol(p, Decl(strictOptionalProperties1.ts, 124, 18))
declare let ox3: { p?: string };
>ox3 : Symbol(ox3, Decl(strictOptionalProperties1.ts, 125, 11))
>p : Symbol(p, Decl(strictOptionalProperties1.ts, 125, 18))
declare let ox4: { p?: string | undefined };
>ox4 : Symbol(ox4, Decl(strictOptionalProperties1.ts, 126, 11))
>p : Symbol(p, Decl(strictOptionalProperties1.ts, 126, 18))
declare let tx1: [string];
>tx1 : Symbol(tx1, Decl(strictOptionalProperties1.ts, 128, 11))
declare let tx2: [string | undefined];
>tx2 : Symbol(tx2, Decl(strictOptionalProperties1.ts, 129, 11))
declare let tx3: [string?];
>tx3 : Symbol(tx3, Decl(strictOptionalProperties1.ts, 130, 11))
declare let tx4: [(string | undefined)?];
>tx4 : Symbol(tx4, Decl(strictOptionalProperties1.ts, 131, 11))
declare function f11<T>(x: { p?: T }): T;
>f11 : Symbol(f11, Decl(strictOptionalProperties1.ts, 131, 41))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 133, 21))
>x : Symbol(x, Decl(strictOptionalProperties1.ts, 133, 24))
>p : Symbol(p, Decl(strictOptionalProperties1.ts, 133, 28))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 133, 21))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 133, 21))
f11(ox1); // string
>f11 : Symbol(f11, Decl(strictOptionalProperties1.ts, 131, 41))
>ox1 : Symbol(ox1, Decl(strictOptionalProperties1.ts, 123, 11))
f11(ox2); // string | undefined
>f11 : Symbol(f11, Decl(strictOptionalProperties1.ts, 131, 41))
>ox2 : Symbol(ox2, Decl(strictOptionalProperties1.ts, 124, 11))
f11(ox3); // string
>f11 : Symbol(f11, Decl(strictOptionalProperties1.ts, 131, 41))
>ox3 : Symbol(ox3, Decl(strictOptionalProperties1.ts, 125, 11))
f11(ox4); // string | undefined
>f11 : Symbol(f11, Decl(strictOptionalProperties1.ts, 131, 41))
>ox4 : Symbol(ox4, Decl(strictOptionalProperties1.ts, 126, 11))
declare function f12<T>(x: [T?]): T;
>f12 : Symbol(f12, Decl(strictOptionalProperties1.ts, 138, 9))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 140, 21))
>x : Symbol(x, Decl(strictOptionalProperties1.ts, 140, 24))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 140, 21))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 140, 21))
f12(tx1); // string
>f12 : Symbol(f12, Decl(strictOptionalProperties1.ts, 138, 9))
>tx1 : Symbol(tx1, Decl(strictOptionalProperties1.ts, 128, 11))
f12(tx2); // string | undefined
>f12 : Symbol(f12, Decl(strictOptionalProperties1.ts, 138, 9))
>tx2 : Symbol(tx2, Decl(strictOptionalProperties1.ts, 129, 11))
f12(tx3); // string
>f12 : Symbol(f12, Decl(strictOptionalProperties1.ts, 138, 9))
>tx3 : Symbol(tx3, Decl(strictOptionalProperties1.ts, 130, 11))
f12(tx4); // string | undefined
>f12 : Symbol(f12, Decl(strictOptionalProperties1.ts, 138, 9))
>tx4 : Symbol(tx4, Decl(strictOptionalProperties1.ts, 131, 11))
declare function f13<T>(x: Partial<T>): T;
>f13 : Symbol(f13, Decl(strictOptionalProperties1.ts, 145, 9))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 147, 21))
>x : Symbol(x, Decl(strictOptionalProperties1.ts, 147, 24))
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 147, 21))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 147, 21))
f13(ox1); // { p: string }
>f13 : Symbol(f13, Decl(strictOptionalProperties1.ts, 145, 9))
>ox1 : Symbol(ox1, Decl(strictOptionalProperties1.ts, 123, 11))
f13(ox2); // { p: string | undefined }
>f13 : Symbol(f13, Decl(strictOptionalProperties1.ts, 145, 9))
>ox2 : Symbol(ox2, Decl(strictOptionalProperties1.ts, 124, 11))
f13(ox3); // { p: string }
>f13 : Symbol(f13, Decl(strictOptionalProperties1.ts, 145, 9))
>ox3 : Symbol(ox3, Decl(strictOptionalProperties1.ts, 125, 11))
f13(ox4); // { p: string | undefined }
>f13 : Symbol(f13, Decl(strictOptionalProperties1.ts, 145, 9))
>ox4 : Symbol(ox4, Decl(strictOptionalProperties1.ts, 126, 11))
f13(tx1); // [string]
>f13 : Symbol(f13, Decl(strictOptionalProperties1.ts, 145, 9))
>tx1 : Symbol(tx1, Decl(strictOptionalProperties1.ts, 128, 11))
f13(tx2); // [string | undefined]
>f13 : Symbol(f13, Decl(strictOptionalProperties1.ts, 145, 9))
>tx2 : Symbol(tx2, Decl(strictOptionalProperties1.ts, 129, 11))
f13(tx3); // [string]
>f13 : Symbol(f13, Decl(strictOptionalProperties1.ts, 145, 9))
>tx3 : Symbol(tx3, Decl(strictOptionalProperties1.ts, 130, 11))
f13(tx4); // [string | undefined]
>f13 : Symbol(f13, Decl(strictOptionalProperties1.ts, 145, 9))
>tx4 : Symbol(tx4, Decl(strictOptionalProperties1.ts, 131, 11))
// Repro from #44388
type Undefinable<T> = T | undefined;
>Undefinable : Symbol(Undefinable, Decl(strictOptionalProperties1.ts, 157, 9))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 161, 17))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 161, 17))
function expectNotUndefined<T>(value: Undefinable<T>): T {
>expectNotUndefined : Symbol(expectNotUndefined, Decl(strictOptionalProperties1.ts, 161, 36))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 163, 28))
>value : Symbol(value, Decl(strictOptionalProperties1.ts, 163, 31))
>Undefinable : Symbol(Undefinable, Decl(strictOptionalProperties1.ts, 157, 9))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 163, 28))
>T : Symbol(T, Decl(strictOptionalProperties1.ts, 163, 28))
if (value === undefined) {
>value : Symbol(value, Decl(strictOptionalProperties1.ts, 163, 31))
>undefined : Symbol(undefined)
throw new TypeError('value is undefined');
>TypeError : Symbol(TypeError, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
}
return value;
>value : Symbol(value, Decl(strictOptionalProperties1.ts, 163, 31))
}
interface Bar {
>Bar : Symbol(Bar, Decl(strictOptionalProperties1.ts, 168, 1))
bar?: number;
>bar : Symbol(Bar.bar, Decl(strictOptionalProperties1.ts, 170, 15))
}
function aa(input: Bar): void {
>aa : Symbol(aa, Decl(strictOptionalProperties1.ts, 172, 1))
>input : Symbol(input, Decl(strictOptionalProperties1.ts, 174, 12))
>Bar : Symbol(Bar, Decl(strictOptionalProperties1.ts, 168, 1))
const notUndefinedVal = expectNotUndefined(input.bar);
>notUndefinedVal : Symbol(notUndefinedVal, Decl(strictOptionalProperties1.ts, 175, 9))
>expectNotUndefined : Symbol(expectNotUndefined, Decl(strictOptionalProperties1.ts, 161, 36))
>input.bar : Symbol(Bar.bar, Decl(strictOptionalProperties1.ts, 170, 15))
>input : Symbol(input, Decl(strictOptionalProperties1.ts, 174, 12))
>bar : Symbol(Bar.bar, Decl(strictOptionalProperties1.ts, 170, 15))
bb(notUndefinedVal);
>bb : Symbol(bb, Decl(strictOptionalProperties1.ts, 177, 1))
>notUndefinedVal : Symbol(notUndefinedVal, Decl(strictOptionalProperties1.ts, 175, 9))
}
declare function bb(input: number): void;
>bb : Symbol(bb, Decl(strictOptionalProperties1.ts, 177, 1))
>input : Symbol(input, Decl(strictOptionalProperties1.ts, 179, 20))

View File

@ -510,3 +510,176 @@ interface Test {
>bar : string | undefined
}
// Strict optional properties and inference
declare let ox1: { p: string };
>ox1 : { p: string; }
>p : string
declare let ox2: { p: string | undefined };
>ox2 : { p: string | undefined; }
>p : string | undefined
declare let ox3: { p?: string };
>ox3 : { p?: string; }
>p : string | undefined
declare let ox4: { p?: string | undefined };
>ox4 : { p?: string | undefined; }
>p : string | undefined
declare let tx1: [string];
>tx1 : [string]
declare let tx2: [string | undefined];
>tx2 : [string | undefined]
declare let tx3: [string?];
>tx3 : [string?]
declare let tx4: [(string | undefined)?];
>tx4 : [(string | undefined)?]
declare function f11<T>(x: { p?: T }): T;
>f11 : <T>(x: { p?: T;}) => T
>x : { p?: T; }
>p : T | undefined
f11(ox1); // string
>f11(ox1) : string
>f11 : <T>(x: { p?: T; }) => T
>ox1 : { p: string; }
f11(ox2); // string | undefined
>f11(ox2) : string | undefined
>f11 : <T>(x: { p?: T; }) => T
>ox2 : { p: string | undefined; }
f11(ox3); // string
>f11(ox3) : string
>f11 : <T>(x: { p?: T; }) => T
>ox3 : { p?: string; }
f11(ox4); // string | undefined
>f11(ox4) : string | undefined
>f11 : <T>(x: { p?: T; }) => T
>ox4 : { p?: string | undefined; }
declare function f12<T>(x: [T?]): T;
>f12 : <T>(x: [T?]) => T
>x : [T?]
f12(tx1); // string
>f12(tx1) : string
>f12 : <T>(x: [T?]) => T
>tx1 : [string]
f12(tx2); // string | undefined
>f12(tx2) : string | undefined
>f12 : <T>(x: [T?]) => T
>tx2 : [string | undefined]
f12(tx3); // string
>f12(tx3) : string
>f12 : <T>(x: [T?]) => T
>tx3 : [string?]
f12(tx4); // string | undefined
>f12(tx4) : string | undefined
>f12 : <T>(x: [T?]) => T
>tx4 : [(string | undefined)?]
declare function f13<T>(x: Partial<T>): T;
>f13 : <T>(x: Partial<T>) => T
>x : Partial<T>
f13(ox1); // { p: string }
>f13(ox1) : { p: string; }
>f13 : <T>(x: Partial<T>) => T
>ox1 : { p: string; }
f13(ox2); // { p: string | undefined }
>f13(ox2) : { p: string | undefined; }
>f13 : <T>(x: Partial<T>) => T
>ox2 : { p: string | undefined; }
f13(ox3); // { p: string }
>f13(ox3) : { p: string; }
>f13 : <T>(x: Partial<T>) => T
>ox3 : { p?: string; }
f13(ox4); // { p: string | undefined }
>f13(ox4) : { p: string | undefined; }
>f13 : <T>(x: Partial<T>) => T
>ox4 : { p?: string | undefined; }
f13(tx1); // [string]
>f13(tx1) : [string]
>f13 : <T>(x: Partial<T>) => T
>tx1 : [string]
f13(tx2); // [string | undefined]
>f13(tx2) : [string | undefined]
>f13 : <T>(x: Partial<T>) => T
>tx2 : [string | undefined]
f13(tx3); // [string]
>f13(tx3) : [string]
>f13 : <T>(x: Partial<T>) => T
>tx3 : [string?]
f13(tx4); // [string | undefined]
>f13(tx4) : [string | undefined]
>f13 : <T>(x: Partial<T>) => T
>tx4 : [(string | undefined)?]
// Repro from #44388
type Undefinable<T> = T | undefined;
>Undefinable : Undefinable<T>
function expectNotUndefined<T>(value: Undefinable<T>): T {
>expectNotUndefined : <T>(value: Undefinable<T>) => T
>value : Undefinable<T>
if (value === undefined) {
>value === undefined : boolean
>value : Undefinable<T>
>undefined : undefined
throw new TypeError('value is undefined');
>new TypeError('value is undefined') : TypeError
>TypeError : TypeErrorConstructor
>'value is undefined' : "value is undefined"
}
return value;
>value : T
}
interface Bar {
bar?: number;
>bar : number | undefined
}
function aa(input: Bar): void {
>aa : (input: Bar) => void
>input : Bar
const notUndefinedVal = expectNotUndefined(input.bar);
>notUndefinedVal : number
>expectNotUndefined(input.bar) : number
>expectNotUndefined : <T>(value: Undefinable<T>) => T
>input.bar : number | undefined
>input : Bar
>bar : number | undefined
bb(notUndefinedVal);
>bb(notUndefinedVal) : void
>bb : (input: number) => void
>notUndefinedVal : number
}
declare function bb(input: number): void;
>bb : (input: number) => void
>input : number

View File

@ -121,3 +121,63 @@ interface Test {
foo?: string; // Should be ok
bar?: string | undefined; // Error
}
// Strict optional properties and inference
declare let ox1: { p: string };
declare let ox2: { p: string | undefined };
declare let ox3: { p?: string };
declare let ox4: { p?: string | undefined };
declare let tx1: [string];
declare let tx2: [string | undefined];
declare let tx3: [string?];
declare let tx4: [(string | undefined)?];
declare function f11<T>(x: { p?: T }): T;
f11(ox1); // string
f11(ox2); // string | undefined
f11(ox3); // string
f11(ox4); // string | undefined
declare function f12<T>(x: [T?]): T;
f12(tx1); // string
f12(tx2); // string | undefined
f12(tx3); // string
f12(tx4); // string | undefined
declare function f13<T>(x: Partial<T>): T;
f13(ox1); // { p: string }
f13(ox2); // { p: string | undefined }
f13(ox3); // { p: string }
f13(ox4); // { p: string | undefined }
f13(tx1); // [string]
f13(tx2); // [string | undefined]
f13(tx3); // [string]
f13(tx4); // [string | undefined]
// Repro from #44388
type Undefinable<T> = T | undefined;
function expectNotUndefined<T>(value: Undefinable<T>): T {
if (value === undefined) {
throw new TypeError('value is undefined');
}
return value;
}
interface Bar {
bar?: number;
}
function aa(input: Bar): void {
const notUndefinedVal = expectNotUndefined(input.bar);
bb(notUndefinedVal);
}
declare function bb(input: number): void;