TypeScript interface [key: string]

前端 未结 2 1750
别跟我提以往
别跟我提以往 2021-01-24 06:35

I\'m trying to write an interface but it keeps popin\' an error:

\"Property \'success\' of type \'boolean\' is not assignable to string index type \'PageableLarave

相关标签:
2条回答
  • 2021-01-24 07:16

    Unfortunately that isn't allowed with the index signature syntax that you're using. When you add the index signature ([key: string]: PageableLaravel) that means that all properties must be PageableLaravel, not just all unspecified properties.

    You can solve this with an intersection type though:

    export interface PageableLaravel {
        path: string;
        current_page: number;
        from: number;   
    }
    
    export type Pageable = {
        success: boolean;
        message: string;
    } & {
        [key: string]: PageableLaravel
    }
    

    TypeScript playground demo

    0 讨论(0)
  • 2021-01-24 07:25

    There's no concrete type in TypeScript that exactly matches what you're asking for. Maybe one day TypeScript will support arbitrary index signatures and negated types, at which point we'd be able to represent something like a "default" property value. But for now, there are only workarounds.


    The intersection type in the other answer is one common workaround which works fairly well for reading properties, but not so much for writing them.


    There is, however, a reasonably straightforward generic type that represents the concept of "some unknown other keys":

    interface BasePageable {
      success: boolean;
      message: string;
    }
    
    type Pageable<K extends keyof any> = BasePageable &
      Record<Exclude<K, keyof BasePageable>, PageableLaravel>;
    

    Here Pageable<K> is generic in K, the name(s) of the extra key(s) whose values you want to be PageableLaravel types. To use this type you might want a helper function so you don't need to manually specify the value of K:

    const asPageable = <P extends Pageable<keyof P>>(p: P) => p;
    

    And here it is in action:

    const works = asPageable({
      success: true,
      message: "hey",
      foo: {
        path: "x",
        current_page: 123,
        from: 1
      }
    });
    
    const flagsImproperValue = asPageable({
      success: true,
      message: "hey",
      foo: 123 // error!
    });
    // Type 'number' is not assignable to type 'PageableLaravel'.
    

    Note that this does not capture the number of extra keys as exactly one. It allows more than one and less than one:

    const allowsExtraKeys = asPageable({
      success: true,
      message: "hey",
      foo: {
        path: "x",
        current_page: 123,
        from: 1
      },
      bar: {
        path: "x",
        current_page: 123,
        from: 1
      }
    });
    
    const allowsMissingKeys = asPageable({
      success: true,
      message: "hey"
    });
    

    Of course, your original index signature would have that issue also. The restriction that there be exactly one key in addition to success and message is expressible in TypeScript but it is ugly and hard to work with. This is probably good enough for your purposes.

    This is still a workaround because it's generic where you might have expected a concrete type. Okay, hope that helps; good luck!

    Link to code

    0 讨论(0)
提交回复
热议问题