I have this TypeScript playground:
export function isBlue<T extends Mesh>(
object: unknown,
type: T | Array<T>,
): object is BlueNodeType<T> {
const array: Array<T> = Array.isArray(type) ? type : [type]
return (
object != null && typeof object === 'object' &&
'type' in object &&
typeof object.type === 'string' &&
array.includes((object as BlueNodeType<T>).type)
)
}
export enum Mesh {
Assertion = 'mesh-assertion',
}
export type BlueBaseType = {
color: 'blue'
}
export type BlueAssertionType = BlueBaseType & {
type: Mesh.Assertion
}
export type BlueMappingType = {
'mesh-assertion': BlueAssertionType
}
export type BlueNodeType<T extends Mesh> = BlueMappingType[T]
It is throwing this error:
Argument of type 'Mesh' is not assignable to parameter of type 'T'.
'Mesh' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Mesh'.(2345)
How do I get this to work? In my real codebase I have a BlueMappingType
with 40 types, so I would like for it to be able to pick the correct type based on the generic type parameter.
CodePudding user response:
Using Array.prototype.includes
is tricky one. In order to make it work, you can try my custom includes
:
const withTuple = <
List extends string[]
>(list: readonly [...List]) =>
(prop: string): prop is List[number] =>
list.includes(prop)
export function isBlue<T extends Mesh>(
object: unknown,
type: T | Array<T>,
): object is BlueNodeType<T> {
const array: Array<T> = Array.isArray(type) ? type : [type]
const includes = withTuple(array)
return (
object != null && typeof object === 'object' &&
'type' in object &&
typeof object.type === 'string' &&
includes(object.type)
)
}
export enum Mesh {
Assertion = 'mesh-assertion',
}
export type BlueBaseType = {
color: 'blue'
}
export type BlueAssertionType = BlueBaseType & {
type: Mesh.Assertion
}
export type BlueMappingType = {
'mesh-assertion': BlueAssertionType
}
export type BlueNodeType<T extends Mesh> = BlueMappingType[T]
withTuple
is just a curried version of Array.prototype.includes
but it works with tuples.
You can check my article for more examples