打字稿负面类型检查

时间:2016-09-05 10:32:39

标签: typescript

在打字稿中:是否可以检查类型预期类型是否不是某种类型?或者创建一个定义不应该存在的方法/道具的界面?

3 个答案:

答案 0 :(得分:1)

在TypeScript编译器中,虽然最终可能会这样做,但仍无法做到这一点。

This issue on the TypeScript project似乎是跟踪此功能请求的主要内容;许多其他类似的问题与它有关。

始终可以在运行时进行这些检查。这可以通过标准检查/断言手动完成。我个人喜欢将JSONSchema用于非平凡的“除X个案例之外的所有内容”或io-ts包,以构建这些类型的运行时验证程序。在TypeScript中,您还可以访问type guard函数,这些函数可用于执行这些验证。

编辑这可以用有限的,不是非常有用的方式实现。使用this articleOmit类型的修改,可以使类型检查器拒绝某些,但不是所有违反类型。

例如,假设您想要“的任何object的类型具有属性cd”。你可以这样表达这种类型:

type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T];  
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>;
type AnyTypeWithoutCorD<T> = Omit<T, keyof T & ( "c" | "d" )>

使用该类型,类型检查器拒绝以下内容:

type MyType = { a: number, b: number, c: number };

// Accepts a generic argument and a parameter; ensures the
// parameter can be constrained into the AnyTypeWithoutCorD type.
function funcGeneric<T>(arg: AnyTypeWithoutCorD<T>) {}

// Accepts a parameter of a known type MyType, constrained 
// into the AnyTypeWithoutCorD type.
function func(arg: AnyTypeWithoutCorD<MyType>) {}

let foo: AnyTypeWithoutCorD<MyType> = { a: 1, b: 1, c: 2 } // Error: type not assignable
func({ a: 1, b: 1, c: 2 }) // Error: type not assignable
funcGeneric<MyType>({ a: 1, b: 1, c: 2 }) // Error: type not assignable

<强>限制:

  • 必须显式枚举输入类型(示例中为MyType)中的所有键。不允许使用索引属性签名;那些导致类型检查器接受Omit个对象而不管它们的字段。例如,如果在上面的示例中将[x: string]: any添加到MyType的规范中,则typechecker会愉快地接受所有参数(& { [x: string]: any }是等效的并且行为方式相同)。如果您正在对您不控制其输入类型的事物执行Omit - 类型验证,则这意味着如果任何输入类型具有索引属性签名,则不会进行验证。
  • 这仅适用于您为Omit类型构造函数提供全新值,或在类型检查中等效“早期”执行某些操作的情况。从先前的赋值或通过类型断言提供数据不会按预期执行Omit验证。
  • 如果您将原始数据提供给使用通用参数化Omit类型的通用函数或类型,并且在调用函数时没有显式声明通用,它将会没有正确推断,因此不会发生Omit验证,因为您的类型不会通过。

例如,下面没有任何工作(类型检查器都是接受):

let bar: MyType = { a: 1, b: 1, c: 2 }
func(bar)
func({ a: 1, b: 1, c: 2 } as MyType)
funcGeneric(bar)
funcGeneric({ a: 1, b: 1, c: 2 })
let ok: AnyTypeWithoutCorD<object> = { a: 1, b: 1, c: 2 }
let ok: AnyTypeWithoutCorD<{ c: number }> = { a: 1, b: 1, c: 2 }
let ok: AnyTypeWithoutCorD<MyType> = { a: 1, b: 1, c: 2 } as MyType
let ok: AnyTypeWithoutCorD<MyType> = bar as MyType

这是我第一次尝试实现/展示这一点,所以人们对TypeScript和自定义类型构造的了解可能会纠正我。拿一粒盐。

<强>结论:

Omit解决方案不值得。

除非您控制所有输入类型到Omit接收器,并保持纪律以保持这些输入类型不含索引属性签名,并确保每次向其中一个接收器提供任何内容时它实际上是拿起Omit约束,这将弊大于利

这是因为有时会正确验证您的类型,这会产生错误的安全感和难以调试,看似不一致的行为。

问题的第一部分中链接的问题,如果完成,将为此用例提供更加强大,可预测和文档化的解决方案。在此之前,请使用运行时检查。

答案 1 :(得分:0)

禁止特定属性

使用never类型告诉TypeScript对象上不应该存在属性。

interface Nameless extends Object {
    name?: never;
}

用法:

declare function foo<T extends Nameless>(argument: T): void;

foo(document);        // OK
foo(1);               // OK
foo({ name: 'Bob' }); // Error

否定对象类型

使用Subtract助手:

type Subtract<T, U> = T & Exclude<T, U>

用法:

declare function process<T>(argument: Subtract<T, Window>): void;

process(1)      // OK
process({})     // OK
process(window) // Error

否定文字

再次使用Subtract助手:

type Subtract<T, U> = T & Exclude<T, U>

用法:

type Insult =
  | 'You silly sod!'
  | 'You son of a motherless goat!';

declare function greet<T extends string>(greeting: Subtract<T, Insult>): void;

greet('Hello, good sir!'); // OK
greet('You silly sod!');   // Error!

答案 2 :(得分:-1)

  

在打字稿中:是否可以检查预期类型是否属于某种类型?

我怀疑你要找的是运行时类型。 TypeScript无法实现此目的,因为在JavaScript中没有标准化方式来执行此操作。

如果您只是寻找简单的类型防护,他们可以正常工作,例如

function foo(bar: string | number){
    if (typeof bar !== 'string') {
        // TypeScript knows its a number!
        return bar.toPrecision(3);
    }
}

更多

键入警卫:https://basarat.gitbooks.io/typescript/content/docs/types/typeGuard.html