简体   繁体   English

TypeScript:避免额外的属性

[英]TypeScript : avoid extra properties

To make it simple, I have an issue with Typescript's "Excess Property Checks" behavior.为简单起见,我对 Typescript 的“过度属性检查”行为有疑问。 I would like to be sure that an object with extra properties is not be accepted by TypeScript.我想确保 TypeScript 不接受具有额外属性的 object。

In my example of a simple interface I could simply pick the available data, but I have a lot of properties and I would like to avoid filtering them on runtime, is there a way?在我的简单接口示例中,我可以简单地选择可用数据,但我有很多属性,我想避免在运行时过滤它们,有什么办法吗?

Here you can find an example code I made for this topic:在这里你可以找到我为这个主题制作的示例代码:

TypeScript Playground TypeScript 游乐场

type LayoutType {
    margin: number;
}

const badData = {
    margin: 23,
    padding: 23,
}

function func(param: LayoutType) {
    console.log(param);
    // Here I want to use property being sure param only contains LayoutType property
}

// OK
func({ margin: 42 })
// OK : padding is detected as unwanted property
func({ margin: 42, padding: 32 })
// KO : bad data shouldn't fit
func(badData)

/* SAME */

// OK : padding is detected as unwanted property
const test1: LayoutType = { margin: 42, padding: 32 };
// KO : bad data shouldn't fit
const test2: LayoutType = badData;

Sounds like you want an Exact type.听起来你想要一个Exact类型。 Typescript doesn't come with one, but it's easy to make: Typescript 没有自带,但是很容易制作:

type Exact<A, B> = A extends B
  ? B extends A
    ? A
    : never
  : never

This basically says that if and A extends B and B extends A then the types are identical, neither are a subset or superset of the other.这基本上是说如果 and A extends B并且B extends A那么类型是相同的,既不是另一个的子集也不是另一个的超集。 So it should allow that type through.所以它应该允许该类型通过。 If they are not identical, then the type is never which prevents that type from being allowed.如果它们不相同,则类型never阻止该类型被允许。

Now you just need to make your function generic, and enforce that argument to exactly the right type:现在你只需要使你的 function 通用,并将该参数强制为正确的类型:

function func<T>(param: Exact<T, LayoutType>) {
    console.log(param);
}
func(badData)
// Argument of type '{ margin: number; padding: number; }'
//   is not assignable to parameter of type 'never'.

Playground 操场

More relevant reading here in Typescript issue #12936更多相关阅读请参阅 Typescript 问题 #12936


Lastly, the reason that an object literal doesn't work, but an object variable does is that the literal is being constructed for a particular type.最后,object 文字不起作用但 object 变量起作用的原因是该文字是为特定类型构造的。 Typescript can't know know about the extra properties because there is no type information for those properties. Typescript 无法知道额外的属性,因为这些属性没有类型信息。 So the typescript program can't use those properties, because they aren't declared to exist.所以 typescript 程序不能使用这些属性,因为它们没有被声明为存在。

However, when the object is a variable and the extra properties are known, then it is a separate but compatible type.然而,当 object 是一个变量并且额外属性已知时,它是一个单独但兼容的类型。 The extra properties may not be used in a function that only accepts the narrow type, but in other code that knows about the wider type the properties can be used.额外的属性可能不会在只接受窄类型的 function 中使用,但在其他知道更宽类型的代码中可以使用这些属性。

This is why this is valid:这就是为什么这是有效的:

const obj1 = { a: 1, b: 2 }
const obj2: { a: number } = obj1

console.log(obj1.b) // b can still be accessed

But this is not:但这不是:

const obj1: { a: number } = { a: 1, b: 2 }
//                                  ^ type error

The reason原因

func({ margin: 42, padding: 32 })

doesn't work, but不起作用,但是

func(badData)

is because of something called " Excess Property Checking " in TypeScript:是因为 TypeScript 中有一个叫做“ Excess Property Checking ”的东西:

Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments. If an object literal has any properties that the “target type” doesn't have, you'll get an error. Object 文字在将它们分配给其他变量或将它们作为 arguments 传递时会得到特殊处理并进行额外的属性检查。如果 object 文字具有“目标类型”没有的任何属性,您将收到错误消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM