如何创建支持两种不同类型的泛型函数



我想创建一个支持两种不同类型的泛型函数,这些类型不能互换使用,但函数将作为辅助函数在两种类型中使用

type  userType = {id : string; user : string}
type  adminType =  {id : string; admin : string}

const copmairByLoop = (firstObject: userType | adminType, secondObject: userType | adminType) => {
for (const key in firstObject) {
if (firstObject[key as keyof userType | adminType] !== secondObject[key as keyof userType | adminType]) {
alert('are not the same');
}
}
};

// use case examples 
const objectUser1 : userType = {id : '234234'; user : 'jack'}
const objectUser2 : userType ={id : '454366546'; user : 'max'}
// copmairByLoop(objectTest1,objectTest2) users are not the same...
// use case examples 
const objectAdmin1 : adminType = {id : '44433'; admin: 'joe'}
const objectAdmin2 : adminType ={id : '7778'; admin: 'alfred'}
// copmairByLoop(objectAdmin1,objectAdmin2) admins are not the same...


// my current refactor 
const copmairByLoop = <T, U>(firstObject: T | U, secondObject:  T | U): never => {
for (const key in firstObject) {
if (firstObject[key as keyof T | U] !== secondObject[key as keyof T | U]) {
alert('are not the same');
}
}
};

请检查沙箱

Codesandbox

经过评论中的讨论,我想我明白你想做什么了。我的解释是,你想有一个单一的函数,返回是否两个用户/管理员是相同的。这样做的典型方法是创建一个单独的函数,取userTypeadminType的并集,如下所示:

type User = {
id: string
user: string
}
type Admin = {
id: string
admin: string
}
function IsEqual(a: User | Admin, b: User | Admin): boolean {
return a.id === b.id
}

缺点是,这通过将可用属性限制为存在于两种类型上的属性来工作(在本例中为id,但假设每个条目无论如何都具有唯一的id属性)。这也意味着你不能检查它们是否都是相同的类型,除非你给这些类型添加了usertype属性或诸如此类的东西。

另一种方法是使用函数重载:
function IsEqual(a: User, b: User): boolean;
function IsEqual(a: Admin, b: Admin): boolean;
function IsEqual(_a: unknown, _b: unknown): boolean {
const a = _a as User & Admin;
const b = _b as User & Admin;
// now both a and b have all three fields;
// any that were not there before have the
// value "undefined"

// if comparing two Users, admin will be undefined on both,
// and undefined == undefined evaluates to true, so that
// gives the expected results
return a.admin === b.admin && a.id === b.id && a.user == b.user;
}
const userA = {id: "a", user: "a"}
const userB = {id: "b", user: "b"}
const adminA = {id: "a", admin: "a"}
const adminB = {id: "b", admin: "b"}
IsEqual(userA, userB) // works; returns false
IsEqual(userA, adminA) // compiler error
IsEqual(adminA, adminB) // works; returns false

请注意,与许多其他支持函数重载的语言不同,Typescript只支持单个实现体,所以你需要手动整理输入以使它们具有可比性。

此外,I建议不要使用for (const key in obj)循环遍历所有属性,因为对于具有多于类型指定的属性的输入对象,没有任何保护(无论是在编译时还是运行时)。如果我们这样做,我们会得到意想不到的结果:

function IsEqual(_a: unknown, _b: unknown): boolean {
const a = _a as User & Admin;
const b = _b as User & Admin;

for (const key in a) {
if (a[key as keyof User] !== b[key as keyof User]) return false
}
return true
}
const user1 = {id: "a", user: "a",}
const user2 = {id: "a", user: "a", foo: "whee"}
IsEqual(user1, user2) // works; returns true
IsEqual(user2, user1) // works; returns false

最新更新