我正在用TypeScript编写一个库,我想检查我的类型定义是否正确。通常,我想检查变量是否具有某种静态类型。我通常这样做:
let expectedToBeString : string = Api.callFunction("param1", 2, []);
但有时,一个类型可能会在我不知情的情况下扩大到any
,所以上面的表达式仍然可以编译。因此,我想通过编写一个故意使类型检查失败的表达式来确保它不会any
。
有时我还想检查我的重载集是否适用于合法类型,但不适用于非法类型,但确保这一点的唯一方法是引发编译错误。
如何验证编译错误是否在应该引发时引发?
有趣的问题。 当条件类型在TypeScript v2.8中发布时,据说本月某个时候(2018年3月)发布,或者现在可以在typescript@next
上提供,您将能够执行以下操作:
type ReplaceAny<T, R> = 0 extends (1 & T) ? R : T
除非T
any
,否则ReplaceAny<T, R>
类型将被T
,在这种情况下,它将R
。 没有正常的T
型应该满足0 extends (1 & T)
,因为1 & T
至少应该和1
一样窄,而且0
不是1
的亚型。 但是 TypeScript 中的any
类型打破了规则:它被认为是所有其他类型的超类型和子类型(或多或少)。 这意味着1 & any
变得any
,0 extends any
是真的。 所以0 extends (1 & T)
的行为就像一个any
探测器。
现在我们可以做一个这样的便利函数:
const replaceAny = <R>() => <T>(x: T): ReplaceAny<T,R> => x as any;
如果你调用replaceAny<{}>()
,它会生成一个函数,该函数将接受任何输入并返回一个类型{}
的值,如果该输入是any
类型。
因此,让我们检查一些场景:
declare const Api: {
callFunctionS(...args: any[]): string,
callFunctionN(...args: any[]): number,
callFunctionA(...args: any[]): any,
}
let expectedToBeString: string;
expectedToBeString =
replaceAny<{}>()(Api.callFunctionS("param1", 2, []));
// okay
expectedToBeString =
replaceAny<{}>()(Api.callFunctionN("param1", 2, []));
// error, number not assignable to string
expectedToBeString =
replaceAny<{}>()(Api.callFunctionA("param1", 2, []));
// error, {} not assignable to string
前两个的行为符合您的预期,expectedToBeString
对callFunctionS()
感到满意,但对callFunctionN()
感到愤怒。 新的行为是它也对callFunctionA()
感到愤怒,因为replaceAny<{}>()
导致返回值的类型是{}
而不是any
,并且{}
不能分配给string
。
希望有帮助;祝你好运!