Typescript: Class property types are ignored when passed as an argument object vs. assigned directly

Created on 14 Apr 2019  路  5Comments  路  Source: microsoft/TypeScript


TypeScript Version: 3.4.0-dev.201xxxxx


Search Terms:
Class, constructor, ignore.
Code
You can see this code from the Scrimba link below, under the "Playground Link".
This example will type check, as expected, no issues.

class Person {
    firstName: string;
    middleName: string;
    lastName: string;

    constructor(data?: any) {
        this.firstName = data.firstName || 'Dylan';
        this.lastName = data.lastName || 'Israel';
        this.middleName = data.middleName;    
    }
}

example1.firstName = 'Dylan';
example1.middleName = 10;  // this will flag in the linter and fail type check as expected
example1.lastName = 'Israel';

With the same code, but passing the object for the new Person, it will not type check:

// ... same code as above

// nothing here will be flagged at all. It also compiles just fine, so it's not just the linter.
const testPerson = new Person({firstName: 10, lastName: false, middleName: 'actually string'})
// A *self-contained* demonstration of the problem follows...
// Test this by running `tsc` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.

Expected behavior:
Class property types would be respected when assigning their values whether passed as an object or assigned individually.

I'm not a TS expert by any means, but this behavior seems contradictory.

Actual behavior:
Class property types are not respected when passed as an argument to a parameter?: any, although they are already assigned on the class.

Playground Link:

I discovered this while taking a intro course on TS here: https://scrimba.com/p/pKwrCg/cbyMBtW

It failed in the linter there, so I reproduced the issue inside VSCode. Both the linter and compiler fail to catch this.

Related Issues:

Question

All 5 comments

I should also note that assigning unique parameters for each respective property, then passing them to the new Person as an argument will respect the typing, even though the same properties are being referenced as in the failing example (this is shown by hovering over; it's clear it's detecting the types).

Exa.

class Person {
    firstName: string;
    middleName: string;
    lastName: string;

    constructor(first: string, last: string, middle: string) {
        this.firstName = first;
        this.lastName = last;
        this.middleName = middle;
    }
}

const newPerson = new Person('Bill', 10, false); /* the last two arguments get flagged by the linter and throw an error during compile, as expected */

If you explicitly type a parameter as any you can assign anything to it. This is the expected behavior.

If you want to pass in an object with the same properties as the class but all optional, you can use the Partial mapped type:

class Person {
    firstName: string;
    middleName: string;
    lastName: string;

    constructor(data: Partial<Person> = {}) {
        this.firstName = data.firstName || 'Dylan';
        this.lastName = data.lastName || 'Israel';
        this.middleName = data.middleName || "";    
    }
}
new Person({firstName: "", lastName: false, middleName: 10}) //err

If you explicitly type a parameter as any you can assign anything to it. This is the expected behavior.

If you want to pass in an object with the same properties as the class but all optional, you can use the Partial mapped type:

class Person {
    firstName: string;
    middleName: string;
    lastName: string;

    constructor(data: Partial<Person> = {}) {
        this.firstName = data.firstName || 'Dylan';
        this.lastName = data.lastName || 'Israel';
        this.middleName = data.middleName || "";    
    }
}
new Person({firstName: "", lastName: false, middleName: 10}) //err

I appreciate the explanation, and I kind of get it, but then why do both examples I gave reference the original properties when you hover over?

It seems like if I understand correctly the constructor is overriding the class properties when using any; is that correct?

It looks like this is a question rather than a bug report. This issue tracker is for tracking bugs and active work on TypeScript itself, rather than a general forum for programmers using TypeScript to get help or ask questions.

You can ask questions on sites like Stack Overflow. We are not able to provide one-on-one support on the issue tracker. Please read the issue template carefully - it has important information on what kinds of reports can be acted on here, as well as links to useful TypeScript resources. Thanks!

@methodbox if you imagine a world where everyone learning TypeScript files "bugs" when they don't understand why something happens, it's one where this issue tracker is completely disregarded by anyone working on TypeScript itself due to the overwhelmingly huge amount of noise that would generate.

We're only able to read these reports at all because the vast majority of people using TS don't use the issue tracker as a forum for asking conceptual questions. I only ask that you do the same. Please consider the context of a popular programming language that is six years old and has 30,000 extant reports - is the thing being described truly novel and likely to have been overlooked for all that time?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dlaberge picture dlaberge  路  3Comments

zhuravlikjb picture zhuravlikjb  路  3Comments

kyasbal-1994 picture kyasbal-1994  路  3Comments

seanzer picture seanzer  路  3Comments

bgrieder picture bgrieder  路  3Comments