microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.99k stars 12.48k forks source link

Type Selection Queries #41109

Open sublimator opened 4 years ago

sublimator commented 4 years ago

This might be a bit of a crazy idea, but here goes: to enable loose coupling between components we sometimes write Pick<Type, 'a' | 'b' | 'c'>

It would be nice if we could create a type query to select properties with a similar syntax to GraphQL:

e.g:

prop: AType[{a, b, c: { d }]

This would be equivalent to

prop: Pick<AType, 'a' | 'b'> & {c: Pick<AType['c'], 'd'>}

How often would you do that in "the real world" ? definitely more often if you could How often should you do that? unclear ?

Some real-world code:

    const testFetch = jest.fn()

    class TestOptions extends GraphQlClient.Options {
      public fetch = testFetch
    }
    const response: Pick<Response, 'ok' | 'json'> = {
      ok: true,
      async json() {
        return { data: { auth: { token: testToken } } }
      }
    }
    testFetch.mockResolvedValue(response)

Pick<Response, 'ok' | 'json'> could be Response[{ok, json}]

edit: that's not a great example use case, cause you could just as well do Partial<Response>

harrysolovay commented 4 years ago

I like this idea a lot. Although I believe this already exists (sort of).

type A = {
  B: {
    C: [
      {D: "E"}
    ]
  }
}

type E = A extends {B: {C: [{D: infer E}]}} ? E : never;

Playground link

If there was going to be a shorthand for generic type params, I'd think it would mirror destructuring (not GraphQL selection sets). Perhaps it could look like this.

type A = {
  B: {
    C: [
      {D: "E"}
    ]
  }
}

type X<{B: {C: {[infer D]}}} extends A> = D;
sublimator commented 4 years ago

@harrysolovay

Neat! Yeah, the idea has a lot of appeal to me in the abstract, just not sure about the impl details.

People like you and the TS team boffins can think of something though :)