我想表示一个参数应该是一个对象或一个简单的值类型(数字,bool,字符串等),但不是一个函数.
如果我使用Object,编译器让我分配一个函数.
var test: Object = () => "a";
Run Code Online (Sandbox Code Playgroud)
如果我使用any,当然也是同样的结果.在这种情况下,是否有类型或技巧可以帮助我?
我的基本目标是在使用Knockout observable时保证安全,这样我就不会忘记打开它们的那些小小的问题:)
2018年11月添加-由于条件类型现在已成为问题!
条件类型为此提供了一种可能的解决方案,因为您可以创建NotFunction条件类型,如下所示:
type NotFunction<T> = T extends Function ? never : T;
Run Code Online (Sandbox Code Playgroud)
其工作原理如下:
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;
Run Code Online (Sandbox Code Playgroud)
这样做的唯一缺点是,必须将变量放在语句的左侧和右侧-尽管如果您犯了以下错误,这是安全的,例如:
// Error - function is not a string
const x: NotFunction<typeof aString> = aFunction;
Run Code Online (Sandbox Code Playgroud)
您可以使用进行运行时检查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);
Run Code Online (Sandbox Code Playgroud)
您几乎可以做到,因为您可以使用重载来允许“多种类型之一”,例如:
class Example {
someMethod(input: number);
someMethod(input: string);
someMethod(input: boolean);
someMethod(input: any) {
}
}
Run Code Online (Sandbox Code Playgroud)
麻烦之处在于:为了允许对象类型,您必须添加someMethod(input: Object);或的重载签名someMethod(input: {});。一旦执行此操作,就将允许使用函数,因为函数是从对象继承的。
如果您可以缩小object到不太通用的范围,则可以为要允许的所有类型简单地添加越来越多的重载(类似)。
您可以使用条件类型在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!
Run Code Online (Sandbox Code Playgroud)
如果类型系统可以决定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
Run Code Online (Sandbox Code Playgroud)
小贴士:
Function类型是一样糟糕any,所以要避免它这是一种定义所有有效(非函数)值然后使用递归定义的方法。我认为这适用于我的情况,并希望适用于遇到此问题的任何其他人。
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]
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3166 次 |
| 最近记录: |