Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Readonly for generic param doesn't work for optional properties #17005

Closed
dfilatov opened this issue Jul 7, 2017 · 5 comments
Closed

Readonly for generic param doesn't work for optional properties #17005

dfilatov opened this issue Jul 7, 2017 · 5 comments
Assignees
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@dfilatov
Copy link

dfilatov commented Jul 7, 2017

TypeScript Version: 2.3.4 or 2.4.1

Code

interface A {
    params?: { name: string; }
}

class Test<T extends A> {
    attrs: Readonly<T>;

    m() {
        this.attrs.params!.name;                    
    }
}

Expected behavior:
no errors

Actual behavior:
Error: Property 'name' does not exist on type 'T["params"]'.

If I remove Readonly or get rid of generic param T then everything will be ok.

@mhegazy mhegazy added the Needs Investigation This issue needs a team member to investigate its status. label Aug 29, 2017
@smhigley
Copy link

I came across this same issue, using v. 2.5.0.

Using strictNullChecks, the following errors:

interface Foo {
  foo?: number;
}

class FooClass<P extends Foo = Foo> {
  properties: Readonly<P>;

  foo(): number {
    const { foo = 42 } = this.properties;
    return foo;
  }
}

Playground link

Removing the generic or getting rid of Readonly both solve the problem, so the following two snippets are error-free:

interface Foo {
  foo?: number;
}

class FooClass {
  properties: Readonly<Foo>;

  foo(): number {
    const { foo = 42 } = this.properties;
    return foo;
  }
}

and

interface Foo {
  foo?: number;
}

class FooClass<P extends Foo = Foo> {
  properties: P;

  foo(): number {
    const { foo = 42 } = this.properties;
    return foo;
  }
}

It appears that const foo in the first example fails to narrow after the destructuring assignment. Hovering over it I see const foo: P["foo"], whereas in the two examples that work, it correctly narrows to const foo: number.

@RyanCavanaugh RyanCavanaugh added Bug A bug in TypeScript and removed Needs Investigation This issue needs a team member to investigate its status. labels Oct 17, 2017
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 2.7 milestone Oct 17, 2017
@mhegazy mhegazy added the Fixed A PR has been merged for this issue label Oct 19, 2017
@agubler
Copy link

agubler commented Mar 22, 2018

@mhegazy @RyanCavanaugh Hey! I am suffering from an issue that seems somewhat related to this original issue using version 2.7.2 and 2.8-rc - I looked through the issue backlog to see if there was an existing issue but struggled to find anything that was a fit (but still apologies if this is a duplicate).

Seems that for a generic (that are being mapped with Readonly<>), it's properties are being narrowed to the value that is assigned as a default during destructuring with strictNullChecks set to true. I have seen this for boolean and enum types.

interface Props {
	foo?: boolean;
}

class Foo<P extends Props = Props> {
	props: Readonly<P> = {} as P;

	myFunc() {
		const { foo = false } = this.props;
                
                // errors because the type of `foo` is narrowed to `false` and cannot be 
                // compared to `true`
		if (foo === true) {}
	}
}

As per the examples from the previous issue above, removing Readonly from the type of props "fixes" the error, so it seems like it is related to mapped types.

Here's a playground link (don't forget to set strictNullCheck to true):

https://www.typescriptlang.org/play/index.html#src=interface%20Props%20%7B%0D%0A%09foo%3F%3A%20boolean%3B%0D%0A%7D%0D%0A%0D%0Aclass%20Foo%3CP%20extends%20Props%20%3D%20Props%3E%20%7B%0D%0A%20%20%20%20props%3A%20Readonly%3CP%3E%20%3D%20%7B%7D%20as%20P%3B%0D%0A%0D%0A%09myFunc()%20%7B%0D%0A%09%09const%20%7B%20foo%20%3D%20false%20%7D%20%3D%20this.props%3B%0D%0A%09%09if%20(foo%20%3D%3D%3D%20true)%20%7B%7D%0D%0A%09%7D%0D%0A%7D

Thanks in advance!

@mhegazy
Copy link
Contributor

mhegazy commented Mar 22, 2018

@agubler please file a new ticket for that one.

@agubler
Copy link

agubler commented Mar 23, 2018

@mhegazy will do, thanks!

@agubler
Copy link

agubler commented Mar 23, 2018

@mhegazy I've created #22823, let me know if you need any more information.

@microsoft microsoft locked and limited conversation to collaborators Jul 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

6 participants