简体   繁体   中英

Limit properties on instantiation of Typescript object

I know per this article that well typed JSON can easily be assigned to an object. For example with the class:

export class User {
    id?: number;
    username: string;

    constructor(username: string) {
        this.username = username;
    }
}

If I had a JSON formatted variable jsonUser :

const jsonUser = {
    username: bob,
};

Then I could easily say:

user: User = <User>jsonUser;

The question I have is how do I write a class, if possible, which limits the properties that class can have. For example:

const jsonUser = {
    username: bob,
    email: bob@bob.bob
};

My User class as defined above does not have email in it. Currently, it allows email to be assigned as a property to my variable of type User . I'd rather it throw an error or not assign it.

I thought this wouldn't be possible, but I found this interesting post in a feature request for exact types in TypeScript.

Essentially you can do this:

export class User {
    id?: number;
    username: string;

    constructor(username: string) {
        this.username = username;
    }
}

type Exact<A extends object> = A & {key: keyof A};

const jsonUser = {
    username: 'bob',
};

const jsonUser2 = {
    username: 'bob',
    id: 2
};

const jsonUser3 = {
    username: 'bob',
    email: 'bob@bob.bob'
};

const user: User = jsonUser as Exact<User>; // OK
const user2: User = jsonUser2 as Exact<User>; // OK
const user3: User = jsonUser3 as Exact<User>; // TypeScript error

The final assignment gives me the following TypeScript error:

Conversion of type '{ username: string; email: string; }' to type 'Exact<User>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  Type '{ username: string; email: string; }' is not comparable to type '{ key: "id" | "username"; }'.
    Property 'key' is missing in type '{ username: string; email: string; }'.

Not the most intuitive message but it does the job.

Credit for the solution goes to Rafał Łużyński (mindbrave) on GitHub.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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