The Wayback Machine - https://web.archive.org/web/20201120005159/https://github.com/microsoft/TypeScript/pull/26797
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

Allow any key type as an index signature parameter type #26797

Open
wants to merge 18 commits into
base: master
from

Conversation

@weswigham
Copy link
Member

@weswigham weswigham commented Aug 30, 2018

This allows, eg, symbol:

interface SymbolMap {
  [x: symbol]: string;
}

interface PropertyMap {
  [x: string | number | symbol]: string;
}

// same as
interface PropertyMap {
  [x: PropertyKey]: string;
}

enums:

enum Cardinal {
  North = "n",
  South = "s",
  West = "w",
  East = "e"
}
interface CardinalDataMap {
  [dir: Cardinal]: number;
}

enum Places {
  None,
  First,
  Second,
  Third
}
interface PlaceMap {
  [dir: Places]: number;
}

literal unions:

interface AdjacencyMap {
  [side: "top" | "bottom" | "left" | "right"]: number;
}

and generics:

interface PartialElementMap<TElements extends keyof HTMLElementTagNameMap> {
  [elem: TElements]: HTMLElement;
}

interface SpyProxy<T> {
  [field: keyof T]: Function;
}

as index signature parameter types.
Much of this functionality also exists in mapped types, except they had trouble shuffling around symbol information since there was no kind of index signature a symbol could map to. Unlike mapped types, however, since these are just index signatures, they can be added into any object type and in multiples.

Fixes #26470
Fixes #1863 (caveat: well-known symbols are not currently checked as part of a symbol index signature! Such checking should fall out from removing the concept of well-known symbols and using unique symbols instead)
Fixes #2491 in the original sense (rather than with mapped types).

Related: #28315

weswigham added 7 commits Aug 24, 2018
@weswigham
Copy link
Member Author

@weswigham weswigham commented Aug 30, 2018

@typescript-bot test this

@typescript-bot
Copy link
Collaborator

@typescript-bot typescript-bot commented Aug 30, 2018

Heya @weswigham, I've started to run the extended test suite on this PR at 2c47d31. You can monitor the build here. It should now contribute to this PR's status checks.

tommy20061222 pushed a commit to tommy20061222/safe-mock that referenced this pull request Oct 28, 2018
(2) typescript 2.9 not allow symbol to be used as index. microsoft/TypeScript#1863. Current there is a PR open to address this issue microsoft/TypeScript#26797
@jhpratt
Copy link

@jhpratt jhpratt commented Nov 22, 2018

@RyanCavanaugh I see you marked this for TS 3.2. Is that still the plan?

@DanielRosenwasser DanielRosenwasser removed this from the TypeScript 3.2 milestone Nov 29, 2018
@motechFR
Copy link

@motechFR motechFR commented Apr 20, 2020

@spaceemotion My understanding of Partial is that it returns the properties as potentially undefined ie. {name?: string} whereas I want to be certain they are present and have a definite list of properties that preserve the original typing ie. go from:

{
name: string,
age: number,
city: string
}

to

{
age: number
}

Thank you for pointing out "Object" as a type to use for extending, it's obvious in retrospect, but sometimes a second set of eyes is what you need!

For anyone reading this, here's a solution (as of TS 3.7.2) to obtain a new object with definite properties that are a subset of an existing generic type:

function sanitiseData<T extends Object, U extends keyof T>(input: T, keysToKeep: U [ ]):  {[key in U]: T[key] } {
 
  let targetObj = {}

  keysToKeep.forEach((key) => {    
    Object.assign(targetObj, {
      [key]: input[key]
    })
  }) 
  return targetObj as  {[key in U]: T[key] }
}
@motechFR
Copy link

@motechFR motechFR commented Apr 20, 2020

Thank you @ProdigySim , seems like Typescript natively supports this with the Pick keyword (I'm looking for positive properties to keep rather than negative properties to remove, which is what Omit does), but anyway thank you for reminding me of their existence

@isiahmeadows
Copy link

@isiahmeadows isiahmeadows commented Sep 8, 2020

What's the status of this PR?

@weswigham
Copy link
Member Author

@weswigham weswigham commented Sep 8, 2020

Still this comment.

@isiahmeadows
Copy link

@isiahmeadows isiahmeadows commented Sep 8, 2020

@weswigham re: #26797 (comment)

Have you considered making {[key: Type]: Value} just sugar for {[P in Type]: Value} where P is some variable not referenced by Value?

@leidegre
Copy link

@leidegre leidegre commented Sep 23, 2020

I really care about this. Is there any way a less general approach to this can be made to work without breakage. For me, it's all about the symbol indexer signature. I just care about being able to say that some objects use symbols the same way they use string properties (this is standard JavaScript stuff). Just want to make symbols first class.

Is there anything I can do to move this forward? I'm willing to commit to fixing this because right now it's a real pain for me to workaround as I happen to use symbols in a lot of places similarly to how you may have used just plain key/string properties today.

@weswigham
Copy link
Member Author

@weswigham weswigham commented Sep 24, 2020

I mean, since we added template literals and pattern templates this release, we'll probably revist it soonish since, symbols aside, types like

interface AriaProps {
  [index: `aria-${string}`]: string;
}

have pretty compelling value (same as regex types as I was advocating for when I first worked on this, but more limited).

@leidegre
Copy link

@leidegre leidegre commented Sep 26, 2020

I mean, since we added template literals and pattern templates this release, we'll probably revist it soonish...

If you get me proper symbol indexers this year, I will be forever grateful.

@mutech
Copy link

@mutech mutech commented Sep 26, 2020

have pretty compelling value (same as regex types as I was advocating for when I first worked on this, but more limited).

The HTTP protocol example for templates is more convincing - great feature - sad that you couldn't push your proposal with regex patterns through. Is there a chance that regexp templates will be added in a later version? That would be awesome to generate code from JSON schema that recognizes pattern properties or type-safe compliance to (some) schema constraints.

This would lift the usefulness of TypeScript to a whole new level.

@weswigham weswigham force-pushed the weswigham:mappedtype-inference-seperate-symbols branch from 38ee04a to 96bb1af Nov 5, 2020
@weswigham
Copy link
Member Author

@weswigham weswigham commented Nov 5, 2020

It was a long and painful merge (mapped type templates actually caused a ton of semantic conflicts, since I reused mapped type machinery in this PR), but now I can finally ask for @typescript-bot pack this

Actual tests/extra implementation updates around pattern literals will be forthcoming, but a playground where the current state is visible should be useful~

@typescript-bot
Copy link
Collaborator

@typescript-bot typescript-bot commented Nov 5, 2020

Heya @weswigham, I've started to run the tarball bundle task on this PR at 96bb1af. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

@typescript-bot typescript-bot commented Nov 6, 2020

Hey @weswigham, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/88729/artifacts?artifactName=tgz&fileId=80EAE52B007884B9DC62FF92B8AE63EA18EE5F3C7EB971D62C2530ADE2B40DBD02&fileName=/typescript-4.2.0-insiders.20201106.tgz"
    }
}

and then running npm install.


There is also a playground for this build.

@weswigham
Copy link
Member Author

@weswigham weswigham commented Nov 6, 2020

nice

@leidegre
Copy link

@leidegre leidegre commented Nov 6, 2020

@weswigham alright, that solves it for me. If you're ever in Stockholm, let my buy you a 🍺 this is very much appreciated!

@ChromeQ
Copy link

@ChromeQ ChromeQ commented Nov 6, 2020

Same if you find yourself in Melbourne, been waiting on this feature a long time. Thank you @weswigham

@leidegre
Copy link

@leidegre leidegre commented Nov 11, 2020

@weswigham is this targeted for inclusion in the 4.2 release?

@DanielRosenwasser will that be this year, or next year?

❤️

@DanielRosenwasser
Copy link
Member

@DanielRosenwasser DanielRosenwasser commented Nov 16, 2020

How does

interface Foo {
    [x: "hello" | "world"]: number;
    [x: "world" | "stuff"]: string;
}

work with this?

@DanielRosenwasser
Copy link
Member

@DanielRosenwasser DanielRosenwasser commented Nov 16, 2020

@leidegre the plan is for 4.2 to be late February, and we'd like this work to be brought in for 4.2.

@weswigham
Copy link
Member Author

@weswigham weswigham commented Nov 17, 2020

As-is, they resolve to concrete properties, and the overlapping property gets a combined type. As we stated at the last design meet we mentioned this topic, given our index signature behavior, it'd be nice if it had separate reading and writing types (which in theory might be implementable for these kinds of manufactured properties without modifying how existing props behave), however that is not what currently occurs (I think we currently always pick the writing type and produce an intersection). We could also layer on an error if we fell that kind of validation is important at declaration sites ("Index signatures only partially overlap and have incompatible types" or the like). You can always try it out in the playground associated with this PR to check the current behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.