Forcing excess-property checking on variable passed to TypeScript function

前端 未结 2 2083
不知归路
不知归路 2020-11-29 09:45

Is there a way to force excess-property checking to happen, not just for an inlined object literal but one that derives from a variable?

For example, suppos

相关标签:
2条回答
  • 2020-11-29 10:20

    I needed this to enforce an object shape in Redux.

    I have combined the answer in this great article and Shannon's answer in this thread here. I think this gives a tiny bit more concise way to implement this:

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

    Here ^^ I put the T extends TExpected in the StrictPropertyCheck, that is all the difference actually but I thought linking the article above would help others landing on this thread.

    Usage for redux action creator:

    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,
      }
    }
    
    0 讨论(0)
  • 2020-11-29 10:24

    Hope this helps, this will cause it to fail. The underlying cause here is Typescripts reliance on structural typing which is alot better than the alternative which is Nominal typing but still has its problems.

    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
    
    0 讨论(0)
提交回复
热议问题