Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript type T or function () => T usage

Tags:

typescript

You can see a demo in this playground.

I've made a simple generic type which can represent either a variable or a function that returns a variable. But, unfortunately, it doesn't work with a typical typeof arg === 'function' check. It produces the following error:

This expression is not callable. Not all constituents of type '(() => T) | (T & Function)' are callable. Type 'T & Function' has no call signatures.

Is there a way to make it work without using type guard function?

type Initializer<T> = T | (() => T)

function correct(arg: Initializer<string>) {
    return typeof arg === 'function' ? arg() : arg
}

function wrong<T>(arg: Initializer<T>) {
    return typeof arg === 'function' ? arg() : arg // error here
}

const isFunction = (arg: any): arg is Function => typeof arg === 'function'

function correct_2<T>(arg: Initializer<T>) {
    return isFunction(arg) ? arg() : arg
}
like image 655
dhmk083 Avatar asked Mar 28 '20 06:03

dhmk083


People also ask

How do you call a function in typescript?

They’re also values, and just like other values, TypeScript has many ways to describe how functions can be called. Let’s learn about how to write types that describe functions. The simplest way to describe a function is with a function type expression . These types are syntactically similar to arrow functions: console. log ( s );

What is the use of construct in typescript?

Constructs a type with all properties of Type set to optional. This utility will return a type that represents all subsets of a given type. Constructs a type consisting of all properties of Type set to required.

What does never mean in typescript?

The never type represents values which are never observed. In a return type, this means that the function throws an exception or terminates execution of the program. never also appears when TypeScript determines there’s nothing left in a union. x; // has type 'never'!

How do I use generics in typescript?

In TypeScript, generics are used when we want to describe a correspondence between two values. We do this by declaring a type parameter in the function signature: By adding a type parameter Type to this function and using it in two places, we’ve created a link between the input of the function (the array) and the output (the return value).


1 Answers

You can write:

type Initializer<T> = T extends any ? (T | (() => T)) : never

function correct<T>(arg: Initializer<T>): T {
    return typeof arg === 'function' ? arg() : arg // works
    // arg is Initializer<T> & Function in the true branch
}

const r1 = correct(2) // const r1: 2
const r2 = correct(() => 2) // const r2: number

In the original version, arg is resolved to (() => T) | (T & Function) in the true branch. TS apparently can't recognize for this union function type, that both constituents are callable. At least in above version, it is clear for the compiler that you can invoke arg after a function check.

Might also be worth to create a github issue for this case in the TypeScript repository - in my opinion T & Function should represent some (wide) type of function.

like image 105
bela53 Avatar answered Sep 20 '22 01:09

bela53