Skip to content

Commit f647b11

Browse files
authored
Use function that doesn't return unknown type (#54713)
1 parent bac475b commit f647b11

File tree

5 files changed

+127
-5
lines changed

5 files changed

+127
-5
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10170,11 +10170,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1017010170
return prop ? getTypeOfSymbol(prop) : undefined;
1017110171
}
1017210172

10173-
function getTypeOfPropertyOrIndexSignature(type: Type, name: __String, addOptionalityToIndex: boolean): Type {
10173+
function getTypeOfPropertyOrIndexSignature(type: Type, name: __String): Type {
10174+
return getTypeOfPropertyOfType(type, name) || getApplicableIndexInfoForName(type, name)?.type || unknownType;
10175+
}
10176+
10177+
/**
10178+
* Similar to `getTypeOfPropertyOrIndexSignature`,
10179+
* but returns `undefined` if there is no matching property or index signature,
10180+
* and adds optionality to index signature types.
10181+
*/
10182+
function getTypeOfPropertyOrIndexSignatureOfType(type: Type, name: __String): Type | undefined {
1017410183
let propType;
1017510184
return getTypeOfPropertyOfType(type, name) ||
10176-
(propType = getApplicableIndexInfoForName(type, name)?.type) && addOptionality(propType, /*isProperty*/ true, addOptionalityToIndex) ||
10177-
unknownType;
10185+
(propType = getApplicableIndexInfoForName(type, name)?.type) &&
10186+
addOptionality(propType, /*isProperty*/ true, /*isOptional*/ true);
1017810187
}
1017910188

1018010189
function isTypeAny(type: Type | undefined) {
@@ -22708,7 +22717,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2270822717
let matched = false;
2270922718
for (let i = 0; i < types.length; i++) {
2271022719
if (include[i]) {
22711-
const targetType = getTypeOfPropertyOrIndexSignature(types[i], propertyName, /*addOptionalityToIndex*/ true);
22720+
const targetType = getTypeOfPropertyOrIndexSignatureOfType(types[i], propertyName);
2271222721
if (targetType && related(getDiscriminatingType(), targetType)) {
2271322722
matched = true;
2271422723
}
@@ -27021,7 +27030,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2702127030
propType = removeNullable && optionalChain ? getOptionalType(propType) : propType;
2702227031
const narrowedPropType = narrowType(propType);
2702327032
return filterType(type, t => {
27024-
const discriminantType = getTypeOfPropertyOrIndexSignature(t, propName, /*addOptionalityToIndex*/ false);
27033+
const discriminantType = getTypeOfPropertyOrIndexSignature(t, propName);
2702527034
return !(discriminantType.flags & TypeFlags.Never) && !(narrowedPropType.flags & TypeFlags.Never) && areTypesComparable(narrowedPropType, discriminantType);
2702627035
});
2702727036
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
discriminateWithMissingProperty.ts(12,5): error TS2345: Argument of type '{ mode: "numeric"; data: Uint8Array; }' is not assignable to parameter of type 'Arg'.
2+
Types of property 'data' are incompatible.
3+
Type 'Uint8Array' is not assignable to type 'number'.
4+
5+
6+
==== discriminateWithMissingProperty.ts (1 errors) ====
7+
type Arg = {
8+
mode: "numeric",
9+
data: number,
10+
} | {
11+
mode: "alphabetic",
12+
data: string,
13+
} | {
14+
data: string | Uint8Array;
15+
}
16+
17+
declare function foo(arg: Arg): void;
18+
foo({ mode: "numeric", data: new Uint8Array([30]) }); // Should error
19+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20+
!!! error TS2345: Argument of type '{ mode: "numeric"; data: Uint8Array; }' is not assignable to parameter of type 'Arg'.
21+
!!! error TS2345: Types of property 'data' are incompatible.
22+
!!! error TS2345: Type 'Uint8Array' is not assignable to type 'number'.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [tests/cases/compiler/discriminateWithMissingProperty.ts] ////
2+
3+
=== discriminateWithMissingProperty.ts ===
4+
type Arg = {
5+
>Arg : Symbol(Arg, Decl(discriminateWithMissingProperty.ts, 0, 0))
6+
7+
mode: "numeric",
8+
>mode : Symbol(mode, Decl(discriminateWithMissingProperty.ts, 0, 12))
9+
10+
data: number,
11+
>data : Symbol(data, Decl(discriminateWithMissingProperty.ts, 1, 20))
12+
13+
} | {
14+
mode: "alphabetic",
15+
>mode : Symbol(mode, Decl(discriminateWithMissingProperty.ts, 3, 5))
16+
17+
data: string,
18+
>data : Symbol(data, Decl(discriminateWithMissingProperty.ts, 4, 23))
19+
20+
} | {
21+
data: string | Uint8Array;
22+
>data : Symbol(data, Decl(discriminateWithMissingProperty.ts, 6, 5))
23+
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
24+
}
25+
26+
declare function foo(arg: Arg): void;
27+
>foo : Symbol(foo, Decl(discriminateWithMissingProperty.ts, 8, 1))
28+
>arg : Symbol(arg, Decl(discriminateWithMissingProperty.ts, 10, 21))
29+
>Arg : Symbol(Arg, Decl(discriminateWithMissingProperty.ts, 0, 0))
30+
31+
foo({ mode: "numeric", data: new Uint8Array([30]) }); // Should error
32+
>foo : Symbol(foo, Decl(discriminateWithMissingProperty.ts, 8, 1))
33+
>mode : Symbol(mode, Decl(discriminateWithMissingProperty.ts, 11, 5))
34+
>data : Symbol(data, Decl(discriminateWithMissingProperty.ts, 11, 22))
35+
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
36+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//// [tests/cases/compiler/discriminateWithMissingProperty.ts] ////
2+
3+
=== discriminateWithMissingProperty.ts ===
4+
type Arg = {
5+
>Arg : { mode: "numeric"; data: number; } | { mode: "alphabetic"; data: string; } | { data: string | Uint8Array; }
6+
7+
mode: "numeric",
8+
>mode : "numeric"
9+
10+
data: number,
11+
>data : number
12+
13+
} | {
14+
mode: "alphabetic",
15+
>mode : "alphabetic"
16+
17+
data: string,
18+
>data : string
19+
20+
} | {
21+
data: string | Uint8Array;
22+
>data : string | Uint8Array
23+
}
24+
25+
declare function foo(arg: Arg): void;
26+
>foo : (arg: Arg) => void
27+
>arg : Arg
28+
29+
foo({ mode: "numeric", data: new Uint8Array([30]) }); // Should error
30+
>foo({ mode: "numeric", data: new Uint8Array([30]) }) : void
31+
>foo : (arg: Arg) => void
32+
>{ mode: "numeric", data: new Uint8Array([30]) } : { mode: "numeric"; data: Uint8Array; }
33+
>mode : "numeric"
34+
>"numeric" : "numeric"
35+
>data : Uint8Array
36+
>new Uint8Array([30]) : Uint8Array
37+
>Uint8Array : Uint8ArrayConstructor
38+
>[30] : number[]
39+
>30 : 30
40+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
type Arg = {
5+
mode: "numeric",
6+
data: number,
7+
} | {
8+
mode: "alphabetic",
9+
data: string,
10+
} | {
11+
data: string | Uint8Array;
12+
}
13+
14+
declare function foo(arg: Arg): void;
15+
foo({ mode: "numeric", data: new Uint8Array([30]) }); // Should error

0 commit comments

Comments
 (0)