打字稿中的泛型,带有用于类型保护的 typeof
generics in typescript with typeof for type guard
你好,我正在学习打字稿,我想创建一个函数来合并对象或字符串,我使用泛型向函数添加额外的信息,以便理解 mergedObj.name 合并两个对象后,如果我删除了字符串的条件,则工作正常,但如果我尝试处理这两种情况,名称显示错误
Property 'name' does not exist on type 'string | ({ name: string; } &
{ age: number; })'. Property 'name' does not exist on type 'string'
我理解这里的 mergedObj 类型是
string | ({
name: string; } & {
age: number; })
但是我如何使用泛型处理这两种情况或多种类型保护?
type ObjectOrString = object | string;
function merge<T extends ObjectOrString , U extends ObjectOrString>(obj1: T, obj2: U) {
if(typeof obj1 === 'string' || typeof obj2 === 'string'){
return obj1.toString() + obj2.toString();
}
return Object.assign(obj1, obj2);
}
let mergedObj = merge({ name: "zeyad" }, { age: 22 }) ;
console.log(mergedObj.name); // Error Here
/* Property 'name' does not exist on type 'string | ({ name: string; }
& { age: number; })'.
Property 'name' does not exist on type 'string'.ts(2339)
*/
let mergedStr = merge('zeyad', ' moamen');
console.log(mergedStr) // zeyad moamen
您必须在某处消除类型歧义,例如:
if (typeof mergedObj !== 'string')
console.log(mergedObj.name);
删除错误
使用 object
类型来表示 hashmap 数据结构不是最佳选择。最好使用 Record<string, unknown>
代替。由于JS中的每一个值都是一个对象,类型object
几乎就是any
类型。
您的函数有 4 个允许的状态:
type ObjectString = Record<string, unknown> | string
function merge<
Obj1 extends string,
Obj2 extends Record<string, unknown>
>(obj1: Obj1, obj2: Obj2): string
function merge<
Obj1 extends Record<string, unknown>,
Obj2 extends string
>(obj1: Obj1, obj2: Obj2): string
function merge<
Obj1 extends string,
Obj2 extends string
>(obj1: Obj1, obj2: Obj2): `${Obj1}${Obj2}`
function merge<
Obj1 extends Record<string, unknown>,
Obj2 extends Record<string, unknown>
>(obj1: Obj1, obj2: Obj2): Obj1 & Obj2
function merge(
obj1: ObjectString,
obj2: ObjectString,
): any {
if (typeof obj1 === 'string' || typeof obj2 === 'string') {
return obj1.toString + obj2.toString()
}
return Object.assign(obj1, obj2)
}
const a = merge('a', 'b') // 'ab'
const b = merge({ a: 1 }, { b: 2 }) // {a:number, b: number}
const c = merge({ a: 1 }, 'c') // string
对于每个状态,我都编写了重载以确保 return 类型被正确推断。
几种类型不使用通用函数就更好了。因为它增加了额外的不必要的类型检查和逻辑。取而代之的是对不同的类型使用不同的函数。更简单、清晰、安全
type Dict<T> = {
[key: string]: T
}
function mergeObjects(obj1: Dict<string | number>, obj2: Dict<string | number>): Dict<string | number> {
return Object.assign(obj1, obj2);
}
function mergeStrings(str1: string, str2: string): string {
return str1 + str2;
}
const mergedObj = mergeObjects({ name: "zeyad" }, { age: 22 }) ;
console.log(mergedObj.name);
const mergedStr = mergeStrings('zeyad', ' moamen');
console.log(mergedStr)
例如,在您的情况下,我可以将 object
作为第一个参数传递给 merge
函数,将 string
作为第二个参数传递给函数。你的函数将 运行 return Object.assign(obj1, obj2);
并且它会给你意想不到的结果:
const obj1 = {a: 'first'};
const obj2 = 'second';
const merge = Object.assign(obj1, obj2);
console.log(merge);
console.log(merge.constructor.name);
反之亦然:
const obj1 = {a: 'first'};
const obj2 = 'second';
const merge = Object.assign(obj2, obj1);
console.log(merge);
console.log(merge.constructor.name);
答案看起来一样,但它们有不同 instance
,这可能是您的应用程序出现意外错误的原因
你好,我正在学习打字稿,我想创建一个函数来合并对象或字符串,我使用泛型向函数添加额外的信息,以便理解 mergedObj.name 合并两个对象后,如果我删除了字符串的条件,则工作正常,但如果我尝试处理这两种情况,名称显示错误
Property 'name' does not exist on type 'string | ({ name: string; } & { age: number; })'. Property 'name' does not exist on type 'string'
我理解这里的 mergedObj 类型是
string | ({ name: string; } & { age: number; })
但是我如何使用泛型处理这两种情况或多种类型保护?
type ObjectOrString = object | string;
function merge<T extends ObjectOrString , U extends ObjectOrString>(obj1: T, obj2: U) {
if(typeof obj1 === 'string' || typeof obj2 === 'string'){
return obj1.toString() + obj2.toString();
}
return Object.assign(obj1, obj2);
}
let mergedObj = merge({ name: "zeyad" }, { age: 22 }) ;
console.log(mergedObj.name); // Error Here
/* Property 'name' does not exist on type 'string | ({ name: string; }
& { age: number; })'.
Property 'name' does not exist on type 'string'.ts(2339)
*/
let mergedStr = merge('zeyad', ' moamen');
console.log(mergedStr) // zeyad moamen
您必须在某处消除类型歧义,例如:
if (typeof mergedObj !== 'string')
console.log(mergedObj.name);
删除错误
使用 object
类型来表示 hashmap 数据结构不是最佳选择。最好使用 Record<string, unknown>
代替。由于JS中的每一个值都是一个对象,类型object
几乎就是any
类型。
您的函数有 4 个允许的状态:
type ObjectString = Record<string, unknown> | string
function merge<
Obj1 extends string,
Obj2 extends Record<string, unknown>
>(obj1: Obj1, obj2: Obj2): string
function merge<
Obj1 extends Record<string, unknown>,
Obj2 extends string
>(obj1: Obj1, obj2: Obj2): string
function merge<
Obj1 extends string,
Obj2 extends string
>(obj1: Obj1, obj2: Obj2): `${Obj1}${Obj2}`
function merge<
Obj1 extends Record<string, unknown>,
Obj2 extends Record<string, unknown>
>(obj1: Obj1, obj2: Obj2): Obj1 & Obj2
function merge(
obj1: ObjectString,
obj2: ObjectString,
): any {
if (typeof obj1 === 'string' || typeof obj2 === 'string') {
return obj1.toString + obj2.toString()
}
return Object.assign(obj1, obj2)
}
const a = merge('a', 'b') // 'ab'
const b = merge({ a: 1 }, { b: 2 }) // {a:number, b: number}
const c = merge({ a: 1 }, 'c') // string
对于每个状态,我都编写了重载以确保 return 类型被正确推断。
几种类型不使用通用函数就更好了。因为它增加了额外的不必要的类型检查和逻辑。取而代之的是对不同的类型使用不同的函数。更简单、清晰、安全
type Dict<T> = {
[key: string]: T
}
function mergeObjects(obj1: Dict<string | number>, obj2: Dict<string | number>): Dict<string | number> {
return Object.assign(obj1, obj2);
}
function mergeStrings(str1: string, str2: string): string {
return str1 + str2;
}
const mergedObj = mergeObjects({ name: "zeyad" }, { age: 22 }) ;
console.log(mergedObj.name);
const mergedStr = mergeStrings('zeyad', ' moamen');
console.log(mergedStr)
例如,在您的情况下,我可以将 object
作为第一个参数传递给 merge
函数,将 string
作为第二个参数传递给函数。你的函数将 运行 return Object.assign(obj1, obj2);
并且它会给你意想不到的结果:
const obj1 = {a: 'first'};
const obj2 = 'second';
const merge = Object.assign(obj1, obj2);
console.log(merge);
console.log(merge.constructor.name);
反之亦然:
const obj1 = {a: 'first'};
const obj2 = 'second';
const merge = Object.assign(obj2, obj1);
console.log(merge);
console.log(merge.constructor.name);
答案看起来一样,但它们有不同 instance
,这可能是您的应用程序出现意外错误的原因