typescript 避免额外的属性

t2a7ltrp  于 2023-10-22  发布在  TypeScript
关注(0)|答案(2)|浏览(106)

我对TypeScript的“Excess Property Checks”行为有一个问题。我想确保具有额外属性的对象不会被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;

操场

x9ybnkn6

x9ybnkn61#

听起来你想要一个Exact类型。Typescript不附带一个,但它很容易制作:

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

这基本上是说,如果和A extends B * 和 * B extends A那么类型是相同的,既不是另一个的子集或超集。所以它应该允许这种类型通过。如果它们不相同,则类型为never,这将阻止该类型被允许。
现在,你只需要让你的函数成为泛型,并将该参数强制为正确的类型:

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'.

操场
更多相关阅读请参见Typescript issue #12936
最后,对象文字不起作用而对象变量起作用的原因是文字是为特定类型构造的。Typescript无法知道额外的属性,因为这些属性没有类型信息。因此,类型脚本程序不能使用这些属性,因为它们没有被声明为存在。
然而,当对象是一个变量,并且额外的属性是已知的,那么它就是一个独立但兼容的类型。在只接受窄类型的函数中可能不会使用额外的属性,但在其他知道更宽类型的代码中,可以使用属性。
这就是为什么这是有效的:

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

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

但这不是:

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

eivnm1vs2#

的原因

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

不起作用,但是

func(badData)

这是因为TypeScript中的“过度属性检查”:

  • 对象字面量 * 得到特殊处理,并在将它们分配给其他变量或将它们作为参数传递时进行 * 多余的属性检查 *。如果一个对象字面量有任何“目标类型”没有的属性,你会得到一个错误。

相关问题