强制对传递给TypeScript函数的变量进行属性过度检查

时间:2019-02-19 22:18:11

标签: typescript

是否有一种方法可以强制进行多余属性检查,而不仅限于内联对象文字,而且还可以从变量派生?

例如,假设我有一个接口和一个函数

interface Animal {
    speciesName: string
    legCount: number,
}

function serializeBasicAnimalData(a: Animal) {
    // something
}


如果我打电话

serializeBasicAnimalData({
    legCount: 65,
    speciesName: "weird 65-legged animal",
    specialPowers: "Devours plastic"
})

我会得到一个错误-对于我的情况,这就是我想要的。我只希望该函数接受通用的动物描述,而无需额外的细节。


另一方面,如果我首先为它创建一个变量,我不会得到错误:

var weirdAnimal = {
    legCount: 65,
    speciesName: "weird 65-legged animal",
    specialPowers: "Devours plastic"
};
serializeBasicAnimalData(weirdAnimal);


所以我的问题是:是否有一种方法可以强制TypeScript对函数参数应用“多余的属性检查”,而不管它是内联对象还是先前已分配给变量的对象?

2 个答案:

答案 0 :(得分:6)

希望这会有所帮助,这将导致它失败。造成这种情况的根本原因是Typescripts依赖于结构化类型,这比名义类型化要好得多,但是仍然存在问题。

type StrictPropertyCheck<T, TExpected, TError> = Exclude<keyof T, keyof TExpected> extends never ? {} : TError;

interface Animal {
    speciesName: string
    legCount: number,
}

function serializeBasicAnimalData<T extends Animal>(a: T & StrictPropertyCheck<T, Animal, "Only allowed properties of Animal">) {
    // something
}

var weirdAnimal = {
    legCount: 65,
    speciesName: "weird 65-legged animal",
    specialPowers: "Devours plastic"
};
serializeBasicAnimalData(weirdAnimal); // now correctly fails

答案 1 :(得分:0)

我需要它来在Redux中强制执行对象形状。

我已将article的出色答案与此线程here的香农的答案结合在一起。我认为这为实现此目标提供了更简洁的方法:

export type StrictPropertyCheck<T, TExpected, TError> = T extends TExpected
  ? Exclude<keyof T, keyof TExpected> extends never
    ? T
    : TError
  : TExpected

在这里^^我将T extends TExpected放在了StrictPropertyCheck中,这实际上是所有区别,但是我认为链接上面的文章将有助于其他人进入该线程。

用于redux操作创建者的用途:

export type Credentials = {
  email: string
  password: string
}

export type StrictCreds<T> = T &
  StrictPropertyCheck<
    T,
    Credentials,
    'ERROR: THERE ARE EXCESS PROPERTIES IN CREDENTIALS OBJECT'
  >

export type AuthActionType =
  | {
      type: AuthAction.LOGIN
      payload: StrictCreds<Credentials>
    }
  | { type: AuthAction.LOGOUT 
export const login = <T>(credentials: StrictCreds<T>): AuthActionType => {
  return {
    type: AuthAction.LOGIN,
    payload: credentials as Credentials,
  }
}