Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
856 views
in Technique[技术] by (71.8m points)

typescript template literal as interface key

Lets say that I want to create a object contain multiple items in typescript as below:

const obj: Items = {
  item1: 'foo',
  item2: 'bar',
  item3: 'baz',
}

How should I declare my Items type so that it's compatible with any number of items? I tried the following with template literals from Typescript 4.1 and it doesn't seem to work:

interface Items {
  [P: `array${number}`]: any;
}

Is it possible to declare a type like this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

UPDATE FOR TS4.4+

TypeScript 4.4 will support index signatures that include pattern template literals, as implemented in microsoft/TypeScript#44512. You will then be able to declare Items as a specific type, like this:

interface Items {
  [key: `item${number}`]: any;
}

And you can verify that it works as desired:

const obj: Items = {
  item1: 'foo',
  item2: 'bar',
  item2021: 'baz',
  item3: 'qux',
};

const objBad: Items = {
  item1: 'foo',
  item2: 'bar',
  itemMMXXI: 'baz', // error!
  //  ~~~~~~~~~ <--
  //  Object literal may only specify known properties,
  //  and 'itemMMXXI' does not exist in type 'Items'
  item3: 'qux'
};

Playground link to code


ANSWER FOR TS4.1-4.3

Pattern template literals of the form `item${number}` (as implemented in microsoft/TypeScript#40598) are not currently allowed as key types, as of TypeScript 4.1.

For now there is no specific type corresponding to your desired Items type. Instead, you could represent it as a constraint on a type and write a helper function asItems() which will only accept inputs that adhere to the constraint:

const asItems = <K extends PropertyKey>(
    obj: { [P in K]: P extends `item${number}` ? any : never }
) => obj;

Each key of the passed-in obj will be checked for whether it is assignable to `item${number}`. If so, the property type is any, and if not, the property type is never. That will tend to cause errors on any offending property:

const obj = asItems({
    item1: 'foo',
    item2: 'bar',
    item2021: 'baz',
    item3: 'qux',
}); // okay

const objBad = asItems({
    item1: 'foo',
    item2: 'bar',
    itemMMXXI: 'baz', // error!
//  ~~~~~~~~~ <-- Type 'string' is not assignable to type 'never'
    item3: 'qux'
});

Playground link to code


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...