TypeScript 严格类/接口

19
我使用TypeScript版本2.3.4。我想编写一个接受必须具有指定字段的对象的函数。但是该对象不应包含任何其他字段。我该如何实现这一点?
现在,只有在我内联定义对象时才能正常工作。但是如果我使用具有额外字段的另一个对象-编译器将允许它。这是完全错误的。
例子:
function foo(arg: { a: string }) { // there is tons of fields actually
  // ...
}

foo ({a: "qwerty"}); // No Error - ok

foo ({a: "qwerty", b: 123}); // Error - ok

let bar = {
  a: "qwerty",
  b: 123
};

foo (bar); // No Error - NOT OK !!!

相同的代码可以使用接口、类、类型声明来编写 - 这是同一个问题。

现在我必须手动从对象中提取字段,以确保没有额外的字段。但是我不能在代码的各个地方(我确实需要这个)扩展这个解决方案到 ~1000 个函数 - 这太混乱了。我正在创建API包装器,并且需要确保没有传递额外或错误的字段到服务器。


看起来这是故意的。请参考此问题此处以获取更多讨论。 - Saravana
Saravana,是啊,我看过这个讨论,但是里面没有回答我的问题。我认为最好在接口方面避免严格性,但是在类方面保留它。 - Harry Burns
5个回答

6
您所要求的功能被称为“精确类型”。
目前正在考虑中,也就是说,还没有被拒绝或接受,讨论仍在进行中。

3

死灵法术。
它将随着typescript 2.4一起推出:

type foo = {
  a:string;
  b:number;
  opt?:string;
}


function test(obj:foo)
{}

test({ a:"", b:123, e:"produceError"});

为了确保它是一个对象,如果所有参数都是可选的:

function test(obj:foo & object)
{}

如果您想传递字符串或其他对象类型:

function test(obj: string | foo & object)
{}

2

有一种方法,但你需要自己实现。它被称为“用户定义的类型保护”,看起来像这样:

interface Test {
    prop: number;
}

function isTest(arg: any): arg is Test {
    return arg && arg.prop && typeof(arg.prop) == 'number';
}

1
最好使用反射来完成(请参见http://blog.wolksoftware.com/decorators-metadata-reflection-in-typescript-from-novice-to-expert-part-4),这样会更短,类似于`check<MyType>(myObject)。或者,在我的情况下是pick<MyType>(myObject)。像underscore/lodash的pick`函数一样工作。 - Harry Burns

2
这是设计上的工作原理,我不确定你能否绕过它。有关更多信息,请参见文档
你还犯了一个错误——你不能百分之百确定发送到服务器的内容。只要浏览器不知道TS的任何信息,某些库就可以注入任何请求所需的内容,例如通过覆盖XmlHttpRequest方法(这至少是Angular的zone.js所做的)。
另一种轻松破坏你意图的方法就是在传递的任何参数前使用<any>
TypeScript旨在改善你的开发过程,但我认为它不能用于像你这样的需求。这通常通过编写适当的测试来实现。

当然我知道TS编译为JS时没有类或类型检查!我需要在开发过程中保护我的方法免受其他开发者的干扰。这都是关于开发的。一个真实的案例: https://codepen.io/HarryBurns/pen/LLWoVa.typescript - Harry Burns

1

使用条件类型可以检查两种类型是否相互扩展 - 类型的一种等价检查。以下是可能的解决方案:

type IsEqual<A,B> = A extends B ? B extends A ? true : false : false
type FooParams = { a: string }

function foo<A extends FooParams>(arg: IsEqual<A, FooParams> extends true ? A : never) {
  // ...
}

foo ({a: "qwerty"}); // No Error - ok

foo ({a: "qwerty", b: 123}); // Error - ok

let bar = {
  a: "qwerty",
  b: 123
};

foo (bar); // Error - ok

PLAYGROUND

{{链接1:游乐场}}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接