Issue
I want to be able to construct a type that accepts the type of another object and returns a different type based on certain properties in that object. This will be easier to explain in code:
// these describe the type of inputs a UI would display
// and their returned values
// e.g. a colorHex UI control should return a string
type Inputs = {
colorHex: string
yearPicker: number
}
// colorHex | yearPicker
type InputTypes = keyof Inputs
// Describes an input. It has a type to define the UI and a label
type Input = {
type: InputTypes
label: string
}
// Describes a composition of inputs. Has an ID and an object with Inputs
type Composition = {
id: string
inputs: Record<string, Input>
}
// Describes a map of compositions
type Compositions = Record<string, Composition>
const comps: Compositions = {
short: {
id: 'short',
inputs: {
bgColor: {
type: 'colorHex',
label: 'BG Color',
},
year: {
type: 'yearPicker',
label: 'Count',
},
},
},
}
// I want to recieve a composition and return a map of input key and the resulting input value type
type InputProps<T extends Composition> = {
[P in keyof T['inputs']]: Inputs[T['inputs'][P]['type']]
}
// The input prop types for comps.short
type ShortProps = InputProps<typeof comps.short>
// What I want ShortProps to equal
type Expected = {
bgColor: string
year: number
}
// ultimately what I want to do with this
const someFn = (props: ShortProps) => {
// props === { bgColor: string; year: number }
}
// this is correct
someFn({ bgColor: '#000', year: 2020 })
// this is incorrect and should result in a type error
someFn({ bgColor: 0, year: '2020' })
Here is a playground link. Notice that the last line does not give a type error when it should.
Solution
You only need to make sure that comps satisfies (or "matches") the type Compositions. Before this, you were overwriting the type information of the object by explicitly annotating it with Compositions. Currently in TS 4.8, we have to use a helper function for this:
function comp<C extends Compositions>(c: C) { return c }
const comps = comp({
short: {
id: 'short',
inputs: {
bgColor: {
type: 'colorHex',
label: 'BG Color',
},
year: {
type: 'yearPicker',
label: 'Count',
},
},
},
});
However, in 4.9+, we can use satisfies keyword:
const comps = {
short: {
id: 'short',
inputs: {
bgColor: {
type: 'colorHex',
label: 'BG Color',
},
year: {
type: 'yearPicker',
label: 'Count',
},
},
},
} satisfies Compositions;
Now you'll get an error on the last line, as desired.
Answered By - caTS
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.