将类型名称转换为实际类型
Convert a type name to the actual type
假设我们有以下枚举
enum PrimayValType {
"string",
"boolean",
"integer",
"float"
}
现在我想写一个函数,输入一个Buffer
和一个PrimaryValType
类型的参数,并根据PrimaryValType
转换缓冲区。如何在 Typescript 中编写这样的函数?
function f(b: Buffer, t: PrimayValType): ??? {
// converts b to a literal based on t
}
const b = Buffer.from('test', 'utf-8');
f(b, PrimayValType.string) // should be of type string
[1]。建议:打字稿中的枚举用于定义命名常量。所以最好用名称来限定字符串文字,例如
enum PrimayValType {
STRING = 'string',
BOOLEAN = 'boolean',
INTEGER = 'integer',
FLOAT = 'float',
}
[2]。试试这个:
function f(b: Buffer, t: PrimayValType=PrimayValType.STRING): number | string | boolean {
const value = b.toString('utf-8');
switch (t) {
case PrimayValType.BOOLEAN:
const isBool = /true|false/.test(value);
if (!isBool) {
throw new TypeError(`${value} is invalid for a boolean type`);
}
return /true/.test(value);
case PrimayValType.INTEGER:
case PrimayValType.FLOAT:
const isNaN = Number.isNaN(value);
if (isNaN) {
throw new TypeError(`${value} is invalid for a numeric type`);
}
return t === PrimayValType.INTEGER ? Number.parseInt(value) : Number.parseFloat(value);
default:
return value;
}
}
essertEqual(f(Buffer.from("3.14", "utf-8"), PrimayValType.FLOAT), 3.14);
assertEqual(f(Buffer.from("3.14", "utf-8"), PrimayValType.INTEGER), 3);
assertTrue(f(Buffer.from("true", "utf-8")));
修改后的答案。打字稿方式。 (我还没有测试过):
const parseBool = (value: string) => {
if (!/true|false/.test(value)) throw new TypeError(`${value} is invalid for a boolean type`);
return /true/.test(value);
};
type PrimType = "string" | "boolean" | "integer" | "float";
type Convert<T> = (str: string) => T;
type Convertors<T> = { [t in PrimType]: Convert<T> };
const convertors: Convertors<number|string|boolean> = {
"integer": parseInt,
"float": parseFloat,
"boolean": parseBool,
"string": (str) => str,
};
const f = (b: Buffer, t: PrimType) => convertors[t](b.toString('utf-8'));
您可以将函数的 return 类型编写为映射类型。首先,将 PrimaryValType
定义为从字符串文字到实际类型的映射:
type PrimaryValType = {
"string": string,
"boolean": boolean,
"integer": number,
"float": number,
}
然后给定一个 K extends keyof PrimaryValType
类型的字符串,我们可以使用映射类型 PrimaryValType[K]
.
将其映射到正确的 return 类型
要将输入解析为正确的类型,您可以打开类型字符串:
function parse<K extends keyof PrimaryValType>(s: string, t: K): PrimaryValType[K] {
switch (t) {
case "integer": return parseInt(s) as PrimaryValType[K];
case "float": return parseFloat(s) as PrimaryValType[K];
case "boolean": return (s === "true") as PrimaryValType[K];
case "string": s as PrimaryValType[K];
default: throw new Error("Illegal t: " + t);
}
}
需要类型断言,因为 Typescript 无法判断 t === 'integer'
那么 K
不能是 'string'
,例如。可以通过将解析器函数存储在对象中来整理代码,如@kmos.w 的回答:
const parsers: { [K in keyof PrimaryValType]: (s: string) => PrimaryValType[K] } = {
"integer": parseInt,
"float": parseFloat,
"boolean": s => s === "true",
"string": s => s,
};
function parse<K extends keyof PrimaryValType>(s: string, t: K): PrimaryValType[K] {
return parsers[t](s) as PrimaryValType[K];
}
出于同样的原因,仍然需要类型断言。
假设我们有以下枚举
enum PrimayValType {
"string",
"boolean",
"integer",
"float"
}
现在我想写一个函数,输入一个Buffer
和一个PrimaryValType
类型的参数,并根据PrimaryValType
转换缓冲区。如何在 Typescript 中编写这样的函数?
function f(b: Buffer, t: PrimayValType): ??? {
// converts b to a literal based on t
}
const b = Buffer.from('test', 'utf-8');
f(b, PrimayValType.string) // should be of type string
[1]。建议:打字稿中的枚举用于定义命名常量。所以最好用名称来限定字符串文字,例如
enum PrimayValType {
STRING = 'string',
BOOLEAN = 'boolean',
INTEGER = 'integer',
FLOAT = 'float',
}
[2]。试试这个:
function f(b: Buffer, t: PrimayValType=PrimayValType.STRING): number | string | boolean {
const value = b.toString('utf-8');
switch (t) {
case PrimayValType.BOOLEAN:
const isBool = /true|false/.test(value);
if (!isBool) {
throw new TypeError(`${value} is invalid for a boolean type`);
}
return /true/.test(value);
case PrimayValType.INTEGER:
case PrimayValType.FLOAT:
const isNaN = Number.isNaN(value);
if (isNaN) {
throw new TypeError(`${value} is invalid for a numeric type`);
}
return t === PrimayValType.INTEGER ? Number.parseInt(value) : Number.parseFloat(value);
default:
return value;
}
}
essertEqual(f(Buffer.from("3.14", "utf-8"), PrimayValType.FLOAT), 3.14);
assertEqual(f(Buffer.from("3.14", "utf-8"), PrimayValType.INTEGER), 3);
assertTrue(f(Buffer.from("true", "utf-8")));
修改后的答案。打字稿方式。 (我还没有测试过):
const parseBool = (value: string) => {
if (!/true|false/.test(value)) throw new TypeError(`${value} is invalid for a boolean type`);
return /true/.test(value);
};
type PrimType = "string" | "boolean" | "integer" | "float";
type Convert<T> = (str: string) => T;
type Convertors<T> = { [t in PrimType]: Convert<T> };
const convertors: Convertors<number|string|boolean> = {
"integer": parseInt,
"float": parseFloat,
"boolean": parseBool,
"string": (str) => str,
};
const f = (b: Buffer, t: PrimType) => convertors[t](b.toString('utf-8'));
您可以将函数的 return 类型编写为映射类型。首先,将 PrimaryValType
定义为从字符串文字到实际类型的映射:
type PrimaryValType = {
"string": string,
"boolean": boolean,
"integer": number,
"float": number,
}
然后给定一个 K extends keyof PrimaryValType
类型的字符串,我们可以使用映射类型 PrimaryValType[K]
.
要将输入解析为正确的类型,您可以打开类型字符串:
function parse<K extends keyof PrimaryValType>(s: string, t: K): PrimaryValType[K] {
switch (t) {
case "integer": return parseInt(s) as PrimaryValType[K];
case "float": return parseFloat(s) as PrimaryValType[K];
case "boolean": return (s === "true") as PrimaryValType[K];
case "string": s as PrimaryValType[K];
default: throw new Error("Illegal t: " + t);
}
}
需要类型断言,因为 Typescript 无法判断 t === 'integer'
那么 K
不能是 'string'
,例如。可以通过将解析器函数存储在对象中来整理代码,如@kmos.w 的回答:
const parsers: { [K in keyof PrimaryValType]: (s: string) => PrimaryValType[K] } = {
"integer": parseInt,
"float": parseFloat,
"boolean": s => s === "true",
"string": s => s,
};
function parse<K extends keyof PrimaryValType>(s: string, t: K): PrimaryValType[K] {
return parsers[t](s) as PrimaryValType[K];
}
出于同样的原因,仍然需要类型断言。