I would like to create a type that only allows properties that start with a given prefix like that:
const example = {
'#prop1': () => {},
'#prop2': () => {}
}
So each Property must be prefixed by a #
in that case. I have played around with »Template Literal Types« within »Mapped Types« like so:
interface WithD {
[s: `#${string}`]: () => void
}
But that yields this error:
An index signature parameter type must be either 'string' or 'number'.
Is there any way to make that happen?
Like @Nadia Chibrikova said, there is no way to build WithD
without knowing example
value up front.
The only way to handle it - is to know (be able to infer) the type you want to validate.
type Validation<T extends Record<string, any>> = {
[Prop in keyof T]: Prop extends `#${string}` ? T[Prop] : never
}
type Assert<T, U> = T extends U ? U extends T ? true : false : false
const example1 = {
'#prop1': () => { },
'#prop2': () => { },
}
const example2 = {
...example1,
'prop3': () => { }
}
type Example1 = typeof example1;
type Example2 = typeof example2;
type Result1 = Assert<Example1, Validation<Example1>> // true
type Result2 = Assert<Example2, Validation<Example2>> // false
const isValid = <T extends Validation<T>>(arg: T) => { }
isValid(example1) // ok
isValid(example2) // expected error
Hence, TS should infer your type either from function argument or from type generic parameter