You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
return true; // `keyof never` is `never`, ergo `never` counts as keyless even though conceptually it contains every key
11883
+
}
11884
+
if (type.flags & TypeFlags.Intersection) {
11885
+
return every((type as IntersectionType).types, canBeKeyless);
11886
+
}
11887
+
if (type.flags & TypeFlags.Union) {
11888
+
return some((type as UnionType).types, canBeKeyless);
11889
+
}
11890
+
if (type.flags & TypeFlags.Conditional) {
11891
+
return canBeKeyless(getTrueTypeFromConditionalType(type as ConditionalType)) || canBeKeyless(getFalseTypeFromConditionalType(type as ConditionalType));
11892
+
}
11893
+
if (type.flags & TypeFlags.Index) {
11894
+
return canBeKeyless((type as IndexType).type);
11895
+
}
11896
+
if (type.flags & TypeFlags.IndexedAccess) {
11897
+
return canBeKeyless((type as IndexedAccessType).objectType);
11898
+
}
11899
+
if (type.flags & TypeFlags.TypeParameter) {
11900
+
const constraint = getConstraintOfTypeParameter(type as TypeParameter);
11901
+
return !constraint || canBeKeyless(constraint);
11902
+
}
11903
+
if (type.flags & TypeFlags.Substitution) {
11904
+
return canBeKeyless((type as SubstitutionType).substitute) && canBeKeyless((type as SubstitutionType).typeVariable);
// As-is, this is effectively sound, but not particularly useful, thanks to all the types it wrongly rejects - only
11975
-
// conditional types with effectively "independent" inference parameters will end up being assignable via this branch, eg
11976
-
// `type InferBecauseWhyNot<T> = T extends (p: infer P1) => any ? T | P1 : never;`
11977
-
// contains a union in the `true` branch, and so while we can't confirm assignability to `P1`, we can confirm assignability to `T`.
11978
-
// A lenient version could be made by replacing `getintersectionType([instantiateType(root.trueType, combinedMapper), instantiateType(root.trueType, mapper)])`
11979
-
// with `instantiateType(root.trueType, combinedMapper)` which would skip checking aginst the type-parametery-ness of the check;
11980
-
// but such a change introduces quite a bit of unsoundness as we stop checking against the type-parameteryness of the `infer` type,
11981
-
// which in turn prevents us from erroring on, eg, unsafe write-position assignments of the constraint of the type.
11982
-
// To be correct here, we'd need to track the implied variance of the infer parameters and _infer_ appropriately (in addition to checking appropriately)
11983
-
// Specifically, we'd need to infer with `InferencePriority.NoConstraint` (or ideally a hypothetical `InferencePriority.SuperConstraint`) for contravariant types,
11984
-
// but continue using the constraints for covariant ones.
// As-is, this is effectively sound, but not particularly useful, thanks to all the types it wrongly rejects - only
12057
+
// conditional types with effectively "independent" inference parameters will end up being assignable via this branch, eg
12058
+
// `type InferBecauseWhyNot<T> = T extends (p: infer P1) => any ? T | P1 : never;`
12059
+
// contains a union in the `true` branch, and so while we can't confirm assignability to `P1`, we can confirm assignability to `T`.
12060
+
// A lenient version could be made by replacing `getintersectionType([instantiateType(root.trueType, combinedMapper), instantiateType(root.trueType, mapper)])`
12061
+
// with `instantiateType(root.trueType, combinedMapper)` which would skip checking aginst the type-parametery-ness of the check;
12062
+
// but such a change introduces quite a bit of unsoundness as we stop checking against the type-parameteryness of the `infer` type,
12063
+
// which in turn prevents us from erroring on, eg, unsafe write-position assignments of the constraint of the type.
12064
+
// To be correct here, we'd need to track the implied variance of the infer parameters and _infer_ appropriately (in addition to checking appropriately)
12065
+
// Specifically, we'd need to infer with `InferencePriority.NoConstraint` (or ideally a hypothetical `InferencePriority.SuperConstraint`) for contravariant types,
12066
+
// but continue using the constraints for covariant ones.
tests/cases/conformance/types/conditional/conditionalTypes2.ts(75,12): error TS2345: Argument of type 'Extract2<T, Foo, Bar>' is not assignable to parameter of type '{ foo: string; bat: string; }'.
25
25
Type 'T extends Bar ? T : never' is not assignable to type '{ foo: string; bat: string; }'.
26
26
Type 'Bar & Foo & T' is not assignable to type '{ foo: string; bat: string; }'.
27
+
tests/cases/conformance/types/conditional/conditionalTypes2.ts(161,11): error TS2322: Type '{ a: number; b: number; }' is not assignable to type '[T] extends [[infer U]] ? U : { b: number; }'.
28
+
tests/cases/conformance/types/conditional/conditionalTypes2.ts(163,11): error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'Distributive<T>'.
29
+
tests/cases/conformance/types/conditional/conditionalTypes2.ts(165,11): error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'Distributive<T & string>'.
30
+
tests/cases/conformance/types/conditional/conditionalTypes2.ts(169,11): error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'Distributive<[T] extends [never] ? { a: number; } : never>'.
T extends object ? { [Q in keyof T]: C2<T[Q], V, E>; } : T;
213
+
214
+
// #26933
215
+
type Distributive<T> = T extends { a: number } ? { a: number } : { b: number };
216
+
function testAssignabilityToConditionalType<T>() {
217
+
const o = { a: 1, b: 2 };
218
+
const x: [T] extends [string] ? { y: number } : { a: number, b: number } = undefined!;
219
+
// Simple case: OK
220
+
const o1: [T] extends [number] ? { a: number } : { b: number } = o;
221
+
// Simple case where source happens to be a conditional type: also OK
222
+
const x1: [T] extends [number]
223
+
? ([T] extends [string] ? { y: number } : { a: number })
224
+
: ([T] extends [string] ? { y: number } : { b: number })
225
+
= x;
226
+
// Infer type parameters: no good
227
+
const o2: [T] extends [[infer U]] ? U : { b: number } = o;
228
+
~~
229
+
!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type '[T] extends [[infer U]] ? U : { b: number; }'.
230
+
// Distributive where T might instantiate to never: no good
231
+
const o3: Distributive<T> = o;
232
+
~~
233
+
!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'Distributive<T>'.
234
+
// Distributive where T & string might instantiate to never: also no good
235
+
const o4: Distributive<T & string> = o;
236
+
~~
237
+
!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'Distributive<T & string>'.
238
+
// Distributive where {a: T} cannot instantiate to never: OK
239
+
const o5: Distributive<{ a: T }> = o;
240
+
// Distributive where check type is a conditional which returns a non-never type upon instantiation with `never` but can still return never otherwise: no good
consto2: [T]extends[[inferU]] ? U : {b: number}=o;
163
+
// Distributive where T might instantiate to never: no good
164
+
consto3: Distributive<T>=o;
165
+
// Distributive where T & string might instantiate to never: also no good
166
+
consto4: Distributive<T&string>=o;
167
+
// Distributive where {a: T} cannot instantiate to never: OK
168
+
consto5: Distributive<{a: T}>=o;
169
+
// Distributive where check type is a conditional which returns a non-never type upon instantiation with `never` but can still return never otherwise: no good
// Simple case where source happens to be a conditional type: also OK
255
+
varx1=x;
256
+
// Infer type parameters: no good
257
+
varo2=o;
258
+
// Distributive where T might instantiate to never: no good
259
+
varo3=o;
260
+
// Distributive where T & string might instantiate to never: also no good
261
+
varo4=o;
262
+
// Distributive where {a: T} cannot instantiate to never: OK
263
+
varo5=o;
264
+
// Distributive where check type is a conditional which returns a non-never type upon instantiation with `never` but can still return never otherwise: no good
265
+
varo6=o;
266
+
}
225
267
226
268
227
269
//// [conditionalTypes2.d.ts]
@@ -304,3 +346,11 @@ declare type B2<T, V> = T extends object ? T extends any[] ? T : {
304
346
declare type C2<T,V,E> = T extends object ? {
305
347
[QinkeyofT]: C2<T[Q],V,E>;
306
348
} : T;
349
+
declare type Distributive<T> = T extends {
350
+
a: number;
351
+
} ? {
352
+
a: number;
353
+
} : {
354
+
b: number;
355
+
};
356
+
declare function testAssignabilityToConditionalType<T>(): void;
0 commit comments