Is there a type in TypeScript for anything but functions?

I would like to say that the parameter should be an object or a simple value type (number, bool, string, etc.), but not a function.

If I use Object, the compiler allows me to assign a function.

var test: Object = () => "a";

If I use any, then the same result, of course, too. Is there a type or trick that can help me in this case?

My main goal is to guarantee safety when using observed knockouts, so that I don’t forget these little parantes to deploy them :)

+4
source share
4 answers

typeof, , , , :

function example(input: any) {
    if (typeof input === 'function') {
        alert('You passed a function!');
    }
}

function someFunction() {
    return 1;
}

// Okay
example({ name: 'Zoltán' });
example(1);
example('a string');
example(someFunction());

// Not okay
example(function () {});
example(someFunction);

, ?

, , " ", :

class Example {
    someMethod(input: number);
    someMethod(input: string);
    someMethod(input: boolean);
    someMethod(input: any) {

    }
}

rub: , someMethod(input: Object); someMethod(input: {});. , , .

object , (yikes) , .

+2

2: , , . , !


typescript 2.8 .

type NotFunc<T> = Exclude<T, Function>
function noFunc <T> (notF: T & NotFunc<T>) { return notF }

const f = () => 2

noFunc(f) // error!
noFunc(f()) // compiles!

, T (.. T ), never, . , .

, , :

// type NotFunc<T> = T extends Function ? never : T
type NotFunc<T> = Exclude<T, Function>

// the imporant cases for us are any and {}
type AnyNotFunc = NotFunc<any> // any
type ObjNotFunc = NotFunc<{}> // {}
type NullNotFunc = NotFunc<null> // never

// some functions, explicitly typed and inferred
const f: Function = () => 2
const ff = () => 2
const g: Function = (): null => null
const gg = (): null => null

// so a function like this won't work:
function badNoFunc <T> (notF: NotFunc<T>) { return notF }

// these all compile, because T is inferred as {} and NotFunc<{}> is just {}
badNoFunc(f)
badNoFunc(g)
badNoFunc(ff)
badNoFunc(gg)

// so need the T & NotFunc<T> to give the compiler a hint as to the type of T
function noFunc <T> (notF: T & NotFunc<T>) { return notF }

// now f is correctly inferred to be Function
noFunc(f) // error! f is assignable to Function
noFunc(g) // error! g is assignable to Function
noFunc(f()) // OK! 2 is not assignable to Function

// but we would expect g() === null to be never since NotFunc<null> === never
noFunc(g()) // OK? even though null is assignable to Function?
noFunc<null>(g()) // Error! Ah, type Function represents () => any but NotFunc<null> is never

// if we use the implicitly typed version, gg, the compiler infers the null return value correctly
noFunc(gg()) // Error! Correct

noFunc(ff) // error! The type is correctly inferred to be function
noFunc(gg) // error! The type is correctly inferred to be function
noFunc(ff()) // OK! 2 is not assignable to Function

:

  • OP , .
  • Function , any,
+3

With typescript 1.8, you can get pretty close if you define a function as something that has all 4 properties: caller, bound, applied and caller:

interface NoCaller {
    caller?: void;
}
interface NoBind {
    bind?: void;
}
interface NoApply {
    apply?: void;
}
interface NoCall {
    call?: void;
}

type NotAFunction = NoCaller | NoBind | NoApply | NoCall; // if it fails all 4 checks it a function


function check<T extends NotAFunction>(t: T) {
    // do something
}

function f() {
}

class T {
}

var o = new T();

check({});
check(o);
check({caller: 'ok', call: 3, apply: this});

//check(f); // fails
//check(T); // also fails: classes are functions, you can't really escape from javascript

Surprisingly, the error message is not so bad:

error TS2345: Argument of type '() => void' is not assignable to parameter of type 'NoCaller | NoBind | NoApply | NoCall'.
  Type '() => void' is not assignable to type 'NoCall'.
    Types of property 'call' are incompatible.
      Type '(thisArg: any, ...argArray: any[]) => any' is not assignable to type 'void'.
0
source

Here is an approach that defines all valid (non-functional) values, and then uses a recursive definition. I think it works for my business and, hopefully, for everyone who comes across this issue.

Typescript example Playground

type NoFunctionValue =
    boolean
    | string
    | number
    | null
    | undefined
    | NoFunctionObject
    | NoFunctionArray

interface NoFunctionObject {
    [key: string]: NoFunctionValue
}

interface NoFunctionArray extends Array<NoFunctionValue> { }

// Try putting a function anywhere in here to see error
const text: NoFunctionObject = {
    bool: true,
    str: 'string',
    num: 7,
    nul: null,
    undef: undefined,
    arr: [true, 'string', 7, null, undefined],
    obj: {
        bool: true,
        str: 'string',
        num: 7,
        nul: null,
        undef: undefined,
        arr: [true, 'string', 7, null, undefined]
    }
} 
0
source

Source: https://habr.com/ru/post/1547436/


All Articles