简体   繁体   English

Typescript:通用类型上不存在属性

[英]Typescript: Property doesn't exist on Generic Type

I'm trying to learn Typescript and I've been following some exercises I've found on the inte.net.我正在尝试学习 Typescript 并且我一直在关注我在 inte.net 上找到的一些练习。 But the feedback on incorrect solutions aren't that great.但是对错误解决方案的反馈并不是那么好。 So I've got the following code but TS keeps complaining that property type is not defined on T:所以我得到了以下代码,但 TS 一直抱怨属性type未在 T 上定义:

interface User {
    type: 'user';
    name: string;
    age: number;
    occupation: string;
}

interface Admin {
    type: 'admin';
    name: string;
    age: number;
    role: string;
}

export type Person = User | Admin;

export const persons: Person[] = [
    { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' },
    { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' },
    { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' },
    { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' },
    { type: 'user', name: 'Wilson', age: 23, occupation: 'Ball' },
    { type: 'admin', name: 'Agent Smith', age: 23, role: 'Anti-virus engineer' }
];

export function filterPersons<T>(persons: T[], personType: string, criteria: T): T[] {
    return persons
        .filter((person) => person.type === personType)
        .filter((person) => {
            let criteriaKeys = Object.keys(criteria) as (keyof T)[];
            return criteriaKeys.every((fieldName) => {
                return person[fieldName] === criteria[fieldName];
            });
        });
}

export const usersOfAge23 = filterPersons<User>(persons, 'user', { age: 23 });
export const adminsOfAge23 = filterPersons<Admin>(persons, 'admin', { age: 23 });

What am I doing wrong here?我在这里做错了什么? T should be a genertic type or in this case User or Admin that is passed right? T 应该是一个通用类型,或者在这种情况下是正确传递的用户或管理员?

In your function declaration, there is one thing you know about T : it extends Person so give this hint to TypeScript:在您的 function 声明中,您知道关于T的一件事:它扩展了Person因此将此提示提供给 TypeScript:

export function filterPersons<T extends Person>(persons: T[], personType: string, criteria: T): T[] {

Your function implementation will work like this but it raises two other errors:您的 function 实现将像这样工作,但会引发另外两个错误:

  • You are passing a Person[] to filterPersons<User> and filterPersons<Admin> which is wider than the required types.您正在将Person[]传递给filterPersons<User>filterPersons<Admin> ,它比所需的类型更宽。 Quick fix: let TypeScript infer the type by omitting it when you call the function: filterPersons快速修复:让 TypeScript 在调用 function 时通过省略它来推断类型: filterPersons
  • The criteria is not a full T , only some properties of it so type it as Partial<T>条件不是完整的T ,只有它的一些属性,因此将其键入Partial<T>

TypeScript playground TypeScript 操场

Inferring types in a filter only works if you don't use an arrow ( source ).仅当您不使用箭头 ( source ) 时, filter中的推断类型才有效。 So you'd need something like:所以你需要这样的东西:

export function filterPersons<T extends Person>(
    persons: Person[], 
    personType: T['type'], 
    criteria: Partial<T>
): T[] {
    const isPersonOf = (person: Person): person is T => person.type === personType;

    return persons
        .filter(isPersonOf)
        .filter((person) => {
            let criteriaKeys = Object.keys(criteria) as (keyof T)[];
            return criteriaKeys.every((fieldName) => {
                return person[fieldName] === criteria[fieldName];
            });
        });
}

Note the type of usersOfAge23 ( User[] ) and adminsOfAge23 ( Admin[] ) when using this implementation.使用此实现时请注意usersOfAge23 ( User[] ) 和adminsOfAge23 ( Admin[] ) 的类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM