Reputation: 5323
How to to make typescript derive generic argument of assertTypof
based on value of expectedType
Namely, I want to apply function below without specifying number
two times
type TypeLiteral = "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
// I know its bad to return generic, but dont know how to make without it
function assertTypeof<T>(expectedType: TypeLiteral, target: any): T {
const actualType = typeof target
if (actualType === expectedType) return target
throw new Error(`Expected ${expectedType}, but got ${actualType}`)
}
const n1 = assertTypeof<number>('number', 1) // fine
const n2 = assertTypeof<number>('number', {}) // error
Upvotes: 4
Views: 1761
Reputation: 51579
You can encode string -> type mapping in an interface, and use indexed access type operator as return type for assertTypeof
:
interface TypeMap {
string: string,
number: number,
boolean: boolean,
symbol: Symbol,
undefined: undefined,
object: object,
function: Function
};
function assertTypeof<N extends keyof TypeMap>(expectedType: N, target: any)
: TypeMap[N] {
const actualType = typeof target
if (actualType === expectedType) return target
throw new Error(`Expected ${expectedType}, but got ${actualType}`)
}
const n1 = assertTypeof('number', 1) // fine
const n2 = assertTypeof('number', {}) // runtime error
Upvotes: 3