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

Type aliases are not displayed when the type alias is defined using an indexed access type #50766

Closed
5 tasks done
jluxenberg opened this issue Sep 13, 2022 · 2 comments
Closed
5 tasks done
Labels
Duplicate An existing issue was already created

Comments

@jluxenberg
Copy link

Suggestion

πŸ” Search Terms

"lookup type"
"zod"
"type alias"

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

It appears that type aliases are not used when the type alias is defined using a lookup type.

In projects using libraries like io-ts and zod, the types generated by tsc (and then used in IDE integrations and .d.ts definition files) are overly verbose and difficult to read. Errors involving the types can be very difficult to understand; the type aliases you have defined are not used, and the entire type itself is used instead.

πŸ“ƒ Motivating Example

Here's a simple illustration of the issue:

type T2 = {_output: {foo: string}};

type TFooObjectDirect = {foo: string};
type TFooObjectIndirect = T2["_output"];

const v1: TFooObjectDirect = {foo: "bar"};
const v2: TFooObjectIndirect = {foo: "bar"};

v1;  /* tsc types this as "const v1: TFooObjectDirect" */
v2;  /* tsc types this as "const v2: {foo: string;}"
        but it should be "const v2: TFooObjectIndirect" */

πŸ”— Playground link

πŸ’» Use Cases

This is a problem in e.g. codebases using io-ts types because:

import * as t from 'io-ts';

const x = t.type({ field1: t.string });
export type T1 = t.TypeOf<typeof x>;

function fn(x: T1) {}

fn({field2: 1});
/* ERROR:
  Argument of type '{ field2: number; }' is not assignable to parameter of type '{ field1: string; }'.
  Object literal may only specify known properties, but 'field2' does not exist in type '{ field1: string; }'. 
  Did you mean to write 'field1'? */

The error should say is not assignable to parameter of type T1, rather than is not assignable to parameter of type '{ field1: string; }'

For small types with a limited number of fields, this isn't really an issue; but for a real-world use case, types can be quite large. This can even trigger TS7056: The inferred type of this node exceeds the maximum length errors as in colinhacks/zod#1040 (comment)

@MartinJohns
Copy link
Contributor

MartinJohns commented Sep 14, 2022

I believe this is a duplicate of #31940. Also related: #32287 (comment)

IIRC TypeScript internally won't create a new type when they encounter one, if the type is already known the existing one is re-used. Only the first occurrence is used. In your case that's { field1: string }, so when it encounters the equal type T1 it re-uses the existing one. This is done for performance reasons.

@andrewbranch andrewbranch changed the title Type aliases are not used when the type alias is defined using a "lookup type" Type aliases are not displayed when the type alias is defined using an indexed access type Sep 16, 2022
@andrewbranch andrewbranch added the Duplicate An existing issue was already created label Sep 16, 2022
@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants