Skip to content

Type checker doesn't understand string literal type in computed property key #15534

New issue

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

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

Already on GitHub? # to your account

Closed
whatisaphone opened this issue May 2, 2017 · 5 comments
Labels
Fixed A PR has been merged for this issue Suggestion An idea for TypeScript

Comments

@whatisaphone
Copy link

TypeScript Version: nightly (2.4.0-dev.20170502)

Code

interface Thing {
  readonly foo: number;
}

function bar(t: Thing) { }

function qux(key: 'foo', value: number) {
  bar({ foo: 5 });  // works
  bar({ [key]: 5 });  // doesn't work
}

Expected behavior:

Both calls typecheck.

Actual behavior:

index.ts(9,7): error TS2345: Argument of type '{ [x: string]: number; }' is not assignable to parameter of type 'Thing'.
  Property 'foo' is missing in type '{ [x: string]: number; }'.
@mhegazy
Copy link
Contributor

mhegazy commented May 3, 2017

Duplicate of #5579

@whatisaphone
Copy link
Author

Here's a more real-world example where this would be helpful, in the context of React:

import * as React from 'react';
import { ChangeEvent } from 'react';

interface LoginState { username: string; password: string; }

export class Login extends React.Component<{}, LoginState> {
  public state: LoginState = { username: '', password: '' };

  private onChange(event: ChangeEvent<HTMLInputElement>, property: keyof LoginState) {
    this.setState({ [property]: event.target.value });  // this doesn't work!
  }

  public render() {
    return (
      <form>
        <input value={this.state.username}
               onChange={(e) => this.onChange(e, 'username')}/>
        <input type="password"
               value={this.state.password}
               onChange={(e) => this.onChange(e, 'password')}/>
        <input type="submit" value="Login"/>
      </form>
    );
  }
}

Relevant definition of setState:

class Component<P, S> {
    setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;
}

Right now the commented line in onChange does not typecheck. The compiler doesn't realize that a { [k: keyof LoginState]: string } can be assigned to a Pick<LoginState, K extends keyof LoginState>.

We currently bypass this by calling this.setState({ ...this.state, [property]: event.target.value }), but this essentially bypasses the typechecker (e.g. calling this.setState({ ...this.state, foo: 'bar' }) compiles as well). It's also passing more keys than necessary to setState, and making it do unnecessary work.

@mhegazy mhegazy reopened this May 4, 2017
@mhegazy mhegazy added Suggestion An idea for TypeScript In Discussion Not yet reached consensus and removed Duplicate An existing issue was already created labels May 4, 2017
@jacobrask
Copy link

I have a similar issue.

type theProp = 'someprop';

const propName: theProp = 'someprop';

interface Some {
    someprop?: number;
}

// Correctly gives error
const literalProp: Some {
    someprop: true,
}

// Could know that the only possible value of `prop` is `someprop` and give error
const dynamicProp: Some = {
    [propName]: true,
}

@Code-Stars
Copy link

This bug should be fixed. I am also having this issue. See this post on Stackoverflow: https://stackoverflow.com/questions/46361905/property-is-missing-in-type-x-string-string

@mhegazy
Copy link
Contributor

mhegazy commented Sep 22, 2017

This should be fixed in by #18317, give typescript@next a try.

@mhegazy mhegazy closed this as completed Sep 22, 2017
@mhegazy mhegazy added Fixed A PR has been merged for this issue and removed In Discussion Not yet reached consensus labels Sep 22, 2017
@mhegazy mhegazy added this to the TypeScript 2.6 milestone Sep 22, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
# for free to subscribe to this conversation on GitHub. Already have an account? #.
Labels
Fixed A PR has been merged for this issue Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants