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
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…