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

Number index signature doesn't work with Readonly generic #17857

Closed
remagpie opened this issue Aug 17, 2017 · 5 comments
Closed

Number index signature doesn't work with Readonly generic #17857

remagpie opened this issue Aug 17, 2017 · 5 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@remagpie
Copy link

TypeScript Version: 2.4.2

Code

type Foo = Readonly<{
  [n: number]: string;
}>;

type Bar = {
  readonly [n: number]: string;
};

function foobar(): void {
  const x: Foo = {
    [0]: 'asdf',
    [1]: 'fdsa',
    [-1]: 'dddd',
  };
  const y: Bar = {
    [0]: 'qwer',
    [1]: 'rewq',
    [-1]: 'eeee',
  };
  const z: string = x[0] + y[0];
}

Expected behavior:
No Error

Actual behavior:
Shows error Element implicitly has an 'any' type because type 'Readonly<{ [n: number]: string; }>' has no index signature. for x[0].

@olegdunkan
Copy link

olegdunkan commented Aug 17, 2017

Readonly is a mapped type and requires named properties in T, Readonly from number index signature is the empty type {}.
(edited)

@aluanhaddad
Copy link
Contributor

aluanhaddad commented Aug 17, 2017

In addition to what @olegdunkan stated, Readonly<T> and other mapped types should be applied at the point of use for correct inference, not instantiated ahead of time and used as annotations.

Consider rewriting the example function as

function foobar(): void {
  const x = Object.freeze({
    0: 'asdf',
    1: 'fdsa',
    [-1]: 'dddd',
  });
  const y = Object.freeze({
    0: 'qwer',
    1: 'rewq',
    [-1]: 'eeee',
  });
  const z: string = x[0] + y[0];
}

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Aug 17, 2017
@remagpie
Copy link
Author

@olegdunkan
But when I use string index instead, I don't get any error.
Like this:

type Foo = Readonly<{
  [s: string]: string;
}>;

type Bar = {
  readonly [s: string]: string;
};

function foobar(): void {
  const x: Foo = {
    ['asdf']: 'asdf',
    ['fdsa']: 'fdsa',
    ['dddd']: 'dddd',
  };
  const y: Bar = {
    ['qwer']: 'qwer',
    ['rewq']: 'rewq',
    ['eeee']: 'eeee',
  };
  const z: string = x['asdf'] + y['qwer'];
}

P.S. I think it should be separate issue, but I don't get any error when I do const z: string = x[0] + y[0]; too.

@olegdunkan
Copy link

olegdunkan commented Aug 18, 2017

Declaration of Readonly is

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

The type of x in var x:keyof {[k:number]:string} is never
The type of x in var x:keyof {[k:string]:string} is string

Then we can assume that in the case of a number index signature tsc produces empty type.
For string index signature next statement is true:

A mapped type takes one of the forms
{ [ P in K ] : T }
{ [ P in K ] ? : T }
{ readonly [ P in K ] : T }
{ readonly [ P in K ] ? : T }
where P is an identifier, K is a type that must be assignable to string

When P is a string literal type, a property with that name is introduced. Otherwise, when P is type string, an index signature is introduced.

#12114 (comment)

@remagpie
Copy link
Author

Oh, it was related to mapped type's operation.
Thank you for reference.

@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

4 participants