-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conditional types #21316
Conditional types #21316
Conversation
# Conflicts: # src/compiler/checker.ts
# Conflicts: # src/compiler/checker.ts # src/compiler/types.ts # tests/baselines/reference/api/tsserverlibrary.d.ts # tests/baselines/reference/api/typescript.d.ts
Sorry if there is a more appropriate place to post this, but thanks for the new (albeit sometimes complicated) ways to express behavior! type IsValidArg<T> = T extends object ? keyof T extends never ? false : true : true;
type NumberOfArgs<T extends Function> =
T extends (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E, f: infer F, g: infer G, h: infer H, i: infer I, j: infer J) => any ? (
IsValidArg<J> extends true ? 10 :
IsValidArg<I> extends true ? 9 :
IsValidArg<H> extends true ? 8 :
IsValidArg<G> extends true ? 7 :
IsValidArg<F> extends true ? 6 :
IsValidArg<E> extends true ? 5 :
IsValidArg<D> extends true ? 4 :
IsValidArg<C> extends true ? 3 :
IsValidArg<B> extends true ? 2 :
IsValidArg<A> extends true ? 1 : 0
) : 0;
function numArgs<T extends Function>(fn: T): NumberOfArgs<T> {
return fn.length as any;
}
declare function exampleFunction(a: number, b: string, c?: any[]): void;
const test = numArgs(exampleFunction); type Promisified<T extends Function> =
T extends (...args: any[]) => Promise<any> ? T : (
T extends (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E, f: infer F, g: infer G, h: infer H, i: infer I, j: infer J) => infer R ? (
IsValidArg<J> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => Promise<R> :
IsValidArg<I> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => Promise<R> :
IsValidArg<H> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => Promise<R> :
IsValidArg<G> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => Promise<R> :
IsValidArg<F> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F) => Promise<R> :
IsValidArg<E> extends true ? (a: A, b: B, c: C, d: D, e: E) => Promise<R> :
IsValidArg<D> extends true ? (a: A, b: B, c: C, d: D) => Promise<R> :
IsValidArg<C> extends true ? (a: A, b: B, c: C) => Promise<R> :
IsValidArg<B> extends true ? (a: A, b: B) => Promise<R> :
IsValidArg<A> extends true ? (a: A) => Promise<R> :
() => Promise<R>
) : never
);
declare function promisify<T extends Function>(fn: T): Promisified<T>;
declare function exampleFunction2(a: number, b: string, c?: any[]): RegExp;
const test2 = promisify(exampleFunction2); |
|
@sirian please post code-fenced blocks instead of screenshots; no one wants to have to type in a dozen lines of code to add comments or observe behavior |
@sirian are you asking a specific question? My example was not meant to be feature-complete, just a result of experimenting with 2.8 for a few minutes. It depends on typescripts
|
@leonadler It was just a notice, that @RyanCavanaugh Mi fault, I was sure I attached code.
|
@leonadler I have an idea! We could use reverse extends check. Look at scratch:
|
@ahejlsberg I think many users will copy types from your examples from #21316 (comment).
|
@sirian You seem to confuse "type A" with "object of type A". Similarily, when you write typeof Object === "function"
TypeName<typeof Object> === "function"
typeof Object.create(Object.prototype) === "object"
TypeName<Object> === "object" class A { }
typeof A === "function"
TypeName<typeof A> === "function"
typeof (new A()) === "object"
TypeName<A> === "object" |
How is it possible to do following? T extends R[] ? BoxedArray<R> : BoxedValue<T> |
@pleerock T extends (infer R)[] |
@princemaple thanks it worked. Actually BoxedArray<T[number]> worked as well but such syntax wasn't obvious to me |
This PR introduces conditional types which add the ability to express non-uniform type mappings. A conditional type selects one of two possible types based on a condition expressed as a type relationship test:
The type above means when
T
is assignable toU
the type isX
, otherwise the type isY
. Evaluation of a conditional type is deferred when evaluation of the condition depends on type variables inT
orU
, but is resolved to eitherX
orY
when the condition depends on no type variables.An example:
Conditional types in which the checked type is a naked type parameter are called distributive conditional types. Distributive conditional types are automatically distributed over union types during instantiation. For example, an instantiation of
T extends U ? X : Y
with the type argumentA | B | C
forT
is resolved as(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)
.In instantiations of a distributive conditional type
T extends U ? X : Y
, references toT
within the conditional type are resolved to individual constituents of the union type (i.e.T
refers to the individual constituents after the conditional type is distributed over the union type). Furthermore, references toT
withinX
have an additional type parameter constraintU
(i.e.T
is considered assignable toU
withinX
).Notice that
T
has the additional constraintany[]
within the true branch ofBoxed<T>
and it is therefore possible to refer to the element type of the array asT[number]
. Also, notice how the conditional type is distributed over the union type in the last example.The distributive property of conditional types can conveniently be used to filter union types:
Conditional types are particularly useful when combined with mapped types:
Combining all of the above to create a
DeepReadonly<T>
type that recursively makes all properties of an object read-only and removes all function properties (i.e. methods):Similar to union and intersection types, conditional types are not permitted to reference themselves recursively (however, indirect references through interface types or object literal types are allowed, as illustrated by the
DeepReadonly<T>
example above). For example the following is an error:For further examples see the tests associated with the PR.
EDIT: See #21496 for type inference in conditional types.
Fixes #12215.
Fixes #12424.