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

error TS2677: Type 'keyof E' is not assignable to type 'string' #23724

Closed
AnyhowStep opened this issue Apr 26, 2018 · 5 comments
Closed

error TS2677: Type 'keyof E' is not assignable to type 'string' #23724

AnyhowStep opened this issue Apr 26, 2018 · 5 comments
Labels
Breaking Change Would introduce errors in existing code

Comments

@AnyhowStep
Copy link
Contributor

TypeScript Version: Version 2.9.0-dev.20180426

Search Terms: keyof not assignable string

Code

//Just a minimal example, not what I am actually doing
function isKey<E> (str : string) : str is keyof E {
    return true;
}

Expected behavior:

Should compile fine. The body of the type guard may actually correctly assert that str is, indeed, keyof E

Works fine on TypeScript 2.8.3

Actual behavior:

error TS2677: A type predicate's type must be assignable to its parameter's type.
  Type 'keyof E' is not assignable to type 'string'.
    Type 'string | number | symbol' is not assignable to type 'string'.
      Type 'number' is not assignable to type 'string'

Playground Link: Works on the playground

Related Issues:

@mhegazy
Copy link
Contributor

mhegazy commented Apr 26, 2018

This is a breaking change in TS 2.9 (documentation should come soon) introduced by #23592. With #23592 keyof now returns all known keys of a types including string, number and symbol keys. and as such, the constraint on keyof E is now string | number | symbol.

If you are interested in getting only the string portions of the keys, use Extract:

function isKey<E>(str: string): str is Extract<keyof E, string> {
    return true;
}

if your function is meant to handle all property names, including symbols, then consider widening the declaration of str:

function isKey<E> (str : string | number | symbol) : str is keyof E {
    return true;
}

@mhegazy mhegazy added the Breaking Change Would introduce errors in existing code label Apr 26, 2018
@ahejlsberg
Copy link
Member

Also, as a temporary measure you can use the new --keyofStringsOnly compiler option to revert to the old behavior.

@AnyhowStep
Copy link
Contributor Author

Thanks for the swift response!

KevinSnyderCodes pushed a commit to KevinSnyderCodes/eventemitter-ts that referenced this issue Jun 25, 2018
In TypeScript 2.9 the constraint of `keyof T` is now `string | number | symbol`. This is not compatible with the type of the `event` parameter in `EventEmitter` methods, which is `string | symbol`.

The compiler option `--keyofStringsOnly` reverts to TypeScript's old `keyof T` contraint, and has been added to `tsconfig.json` to resolve this breaking change.

More info: microsoft/TypeScript#23724
thiagodp added a commit to thiagodp/concordialang that referenced this issue Feb 22, 2019
Because of  the `enum-util` library `1.2.0` and the TS2677 error, detailed in
microsoft/TypeScript#23724
@abdatta
Copy link

abdatta commented Jun 4, 2020

However, if I specifically mention that my type has only string keys like this:

interface A { [k: string]: any; }
type b = keyof A;

still, I get the type of b as string | number as seen in the IntelliSense on vs code:
image
Why is that so? Why is it not string only?
Typescript used: 3.9.3

@SLGShark6
Copy link

For typescript 4, I use this in place of keyof as a current workaround to get accurate key types

type KeyTypes<T> = {
    [K in keyof T]-?: K extends string ?
        string :
        K extends number ?
            number :
            K extends symbol ?
                symbol :
                never
}[keyof T];

type KeyOfType<T, KeyType extends string | number | symbol = KeyTypes<T>> = Extract<keyof T, KeyType>;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaking Change Would introduce errors in existing code
Projects
None yet
Development

No branches or pull requests

5 participants