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

Index signatures prevent automatic typing of e.g. JSON for interfaces and classes, but not types. #19963

Closed
cmcaine opened this issue Nov 13, 2017 · 1 comment
Labels
Question An issue which isn't directly actionable in code

Comments

@cmcaine
Copy link

cmcaine commented Nov 13, 2017

TypeScript Version: Version 2.7.0-dev.20171112

I would like to restrict the input to a function to objects that can be serialised, and I've got it working OK for types, but not for classes or interfaces: I'm told they don't have an index signature.

This is related to issue #1897.

The motivation is that the firefox webextension storage API will only serialise certain objects.

A small example:

Code

declare namespace browser.storage {
    // Non-firefox implementations don't accept all these types
    type StorageValue = 
        string |
        number |
        boolean |
        // ...
        StorageArray |
        StorageMap |
        StorageSet |
        StorageObject;

    // The Index signature makes casting to/from classes or interfaces a pain.
    // Custom types are OK.
    interface StorageObject {
        [key: string]: StorageValue;
    }

    // These have to be interfaces rather than types to avoid a circular
    // definition of StorageValue
    interface StorageArray extends Array<StorageValue> {}
    interface StorageMap extends Map<StorageValue,StorageValue> {}
    interface StorageSet extends Set<StorageValue> {}

    type StorageArea = {
        set: (keys: StorageObject) => Promise<void>,
	// ...
    };

    const sync: StorageArea;
}

type A = {
  prop: string[];
}

interface B {
  prop: string[];
}

class C {
  constructor(public prop: string[]) {}
}

interface D extends browser.storage.StorageObject {
  prop: string[];
}

const a: A = { prop: [] }
const b: B = { prop: [] }
const c = new C([])
const d: D = { prop: [] }

browser.storage.sync.set({ a }) // Works
browser.storage.sync.set({ b }) // Fails: no index signature
browser.storage.sync.set({ c }) // Fails: no index signature
browser.storage.sync.set({ d }) // Works

a.foo = 1 // Property 'foo' does not exist on type 'A'.
b.foo = 1 // Property 'foo' does not exist on type 'B'.
c.foo = 1 // Property 'foo' does not exist on type 'C'.
d.foo = 1 // No error (this is bad)

Errors:

example.ts(51,26): error TS2345: Argument of type '{ b: B; }' is not assignable to parameter of type 'StorageObject'.
  Property 'b' is incompatible with index signature.
    Type 'B' is not assignable to type 'StorageValue'.
      Type 'B' is not assignable to type 'StorageObject'.
        Index signature is missing in type 'B'.
example.ts(52,26): error TS2345: Argument of type '{ c: C; }' is not assignable to parameter of type 'StorageObject'.
  Property 'c' is incompatible with index signature.
    Type 'C' is not assignable to type 'StorageValue'.
      Type 'C' is not assignable to type 'StorageObject'.
        Index signature is missing in type 'C'.
example.ts(55,3): error TS2339: Property 'foo' does not exist on type 'A'.
example.ts(56,3): error TS2339: Property 'foo' does not exist on type 'B'.
example.ts(57,3): error TS2339: Property 'foo' does not exist on type 'C'.

In addition to this issue, I'd also like to express that instances of a class can be stored (you can't store objects with functions, but prototypes and constructors are ignored).

This bug is tracked on the web-ext-types repo (that I maintain) at synecdokey/web-ext-types#38 (comment)

Expected behavior:

Some feature exists to suit the above use case.

Actual behavior:

See example

Thanks for yo time

@mhegazy mhegazy added the Question An issue which isn't directly actionable in code label Nov 13, 2017
@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@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

3 participants