Suggestion
π Search Terms
Call function type
Invoke function type
Function return type
Generic function return type
Simplify extends conditions
β
Viability Checklist
My suggestion meets these guidelines:
β Suggestion
Allow callable function types invoking on type level. The logic behind it is the same as we have for usual function calling
interface One {
(): string
}
type Result = One() // Result is string
If function type has arguments we must pass them as well, but use types as argument
interface Data {
name: string
}
type One = (value: number, data: Data) => boolean
type Result = One(number, Data) // Result is boolean
The same logic with generics
interface Data {
name: string
}
type One = <T>(value: number, data: T) => T
type Result = One<Data>(number, Data) // Result is Data
type Result = One(number, Data) // Result is Data because of type inference
type Result2 = One(number, boolean) // Result is boolean
However, there is a problem when the type itself has a generic
type One<V> = <T>(value: V, data: T) => T
// Implicitly merge them in one row?
type Result = One<number, Data>(number, Data)
// Think about some other syntax ?
type Result = One<number><Data>(number, Data)
// Surround by brackets?
type Result = (One<number>)<Data>(number, Data)
π Motivating Example
Typescript has callable types, i.e.
interface One{
(value: string): string
}
type Two = () => string
and when we need to to get the return type we can use ReturnType type to inference the type
interface One {
(value: string): string
}
type Result = ReturnType<One>
But there are problems when you have overloading
interface One {
(value: string): string
(value: number): number
}
type Result = ReturnType<One>
The things becomes even more complex if you have generics
interface One {
<T>(value: T): T
}
type Result = ReturnType<One>
The Result will be just unknown
π» Use Cases
We will be able to create a type of what function is returning:
declare function createData(condition: 'a'): { a: number; b: number }
declare function createData(condition: 'b'): { c: number; d: number }
type CreateData = typeof createData
type DataA = CreateData('a') // DataA is { a: number; b: number }
type DataB = CreateData('b') // DataB is { c: number; d: number }
We will be able to deal with generic functions
declare function factory<T>(data: T): { getValue(): T; setValue(value: T): void }
type Factory = typeof factory
type MyFactory1 = Factory({ name: string }) // MyFactory1 is { getValue(): { name: string }; setValue(value: { name: string }): void }
type MyFactory2 = Factory({ email: string }) // MyFactory2 is { getValue(): { email: string }; setValue(value: { email: string }): void }
We can simplify extends conditions. For example we have a type with a lot of ? conditions. If there are a lot of conditions it is becomes harder to read them.
interface Data {
name: string
}
type SomeCondition<T> = T extends number ? 'number' : T extends Data ? 'data' : T extends string ? 'string' : unknown
and since functions can have overloading we can use it as switch case
interface Data {
name: string
}
interface SomeCondition {
(value: number): 'number'
(value: Data): 'data'
(value: string): 'string'
// Works as default case
(...value: any[]): unknown
}
// or
interface SomeCondition {
<T extends number>(value: T): 'number'
<T extends Data>(value: T): 'data'
<T extends string>(value: T): 'string'
// Works as default case
(...value: any[]): unknown
}
type A = SomeCondition(number) // A is 'number'
type B = SomeCondition(Data) // B is 'data'
type C = SomeCondition(string) // C is 'string'
type D = SomeCondition(true) // D is unknown
So it works exactly the same as we would just normally call functions
declare const data: Data
declare const logic: SomeCondition
const a = logic(1) // a is 'number'
const b = logic(data) // b is 'data'
const c = logic('foo') // c is 'string'
const d = logic(true) // d is unknown
Suggestion
π Search Terms
Call function type
Invoke function type
Function return type
Generic function return type
Simplify extends conditions
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
Allow callable function types invoking on type level. The logic behind it is the same as we have for usual function calling
If function type has arguments we must pass them as well, but use types as argument
The same logic with generics
However, there is a problem when the type itself has a generic
π Motivating Example
Typescript has callable types, i.e.
and when we need to to get the return type we can use
ReturnTypetype to inference the typeBut there are problems when you have overloading
The things becomes even more complex if you have generics
The
Resultwill be justunknownπ» Use Cases
We will be able to create a type of what function is returning:
We will be able to deal with generic functions
We can simplify
extendsconditions. For example we have a type with a lot of?conditions. If there are a lot of conditions it is becomes harder to read them.and since functions can have overloading we can use it as switch case
So it works exactly the same as we would just normally call functions