代码之家  ›  专栏  ›  技术社区  ›  Zev Spitz

键入“不可调用”[重复]

  •  1
  • Zev Spitz  · 技术社区  · 6 年前

    我想表示参数表应该是一个对象或一个简单的值类型(数字、布尔值、字符串等),而不是一个函数。

    Object ,编译器让我分配一个函数。

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

    any ,当然也是同样的结果。在这种情况下,有什么类型或技巧可以帮助我吗?

    我的基本目标是保证使用击倒观测值时的安全性,这样我就不会忘记那些小小的妄想来解开它们:)

    0 回复  |  直到 10 年前
        1
  •  11
  •   Fenton    6 年前

    新功能答案

    添加于2018年11月-因为条件类型现在是一件事了!

    NotFunction 条件类型,如下所示:

    type NotFunction<T> = T extends Function ? never : T;
    

    其工作原理如下:

    const aFunction = (input: string) => input;
    const anObject = { data: 'some data' };
    const aString = 'data';
    
    // Error function is not a never
    const x: NotFunction<typeof aFunction> = aFunction;
    
    // OK
    const y: NotFunction<typeof anObject> = anObject;
    const z: NotFunction<typeof aString> = aString;
    

    唯一的缺点是必须将变量放在语句的左侧和右侧,但如果您犯了以下错误,则会有安全性:

    // Error - function is not a string
    const x: NotFunction<typeof aString> = aFunction;
    

    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) {
    
        }
    }
    

    问题来了:为了允许对象类型,您必须添加 someMethod(input: Object); someMethod(input: {});

    如果你能缩小范围 object 对于一些不那么一般的东西,您可以简单地为您想要允许的所有类型添加越来越多的重载(yikes)。

        2
  •  9
  •   grooveplex a_r_m    5 年前

    conditional types

    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 Function (即。, T型 never ,这是一个编译时错误。否则,类型将为 T型 你的代码将被编译。

    // 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
    

    1. 警察可以为所欲为
    2. 功能 类型和 any ,所以要避免
        3
  •  4
  •   Steve Ladavich    7 年前

    下面是一种定义所有有效(非函数)值,然后使用递归定义的方法。我认为这适用于我的情况,也希望适用于任何遇到这个问题的人。

    Example on Typescript 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]
        }
    } 
    
        4
  •  1
  •   artem    8 年前

    在typescript 1.8中,如果将函数定义为具有以下4个属性的函数,则可以非常接近:

    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's 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
    

    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'.