microsoft / microsoft/TypeScript

Unexpected type assertion result

Open
#32,653 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Needs Investigation
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
2d 4h
Merged PRs (30d)
132

Description

TypeScript Version: 3.6.0-dev.20190801

Search Terms:

  • type assertion absolute import
  • type assertion import
  • type cast absolute import
  • type cast import
  • type assertion pick

Code

Repo: https://github.com/klemenoslaj/typescript-type-assertion

generated/types.d.ts

export interface TypeD {
  da: string;
  db: string;
  dc: string;
}

export interface Test { 
  a: string;
  b: string;
  c: string;
  d?: { __private: 'd' } & TypeD;
}

src/index.model.ts

import { Test } from 'generated/types';

type DType = NonNullable<Test['d']>;
export type Model = Pick<DType, keyof Exclude<DType, '__private'>>;

src/index.ts

import { Model } from './index.model';

export class A {
    value = <Model>{};
}

dist/index.model.d.ts

import { Test } from 'generated/types';
declare type DType = NonNullable<Test['d']>;
export declare type Model = Pick<DType, keyof Exclude<DType, '__private'>>;
export {};

dist/index.d.ts

export declare class A {
    value: Pick<{
        __private: "d";
    } & import("../generated/types").TypeD, "__private" | "da" | "db" | "dc">;
}

Expected behavior:

I would expect that dist/index.d.ts type definitions would result in:

import { Model } from './index.model';
export declare class A {
    value: Model;
}

In fact, this is the result of type definitions, if I change value = <Model>{}; to value: Model = <Model>{};.

Why doesn't typescript use Model directly when type asserting?

Actual behavior:

Results in:

export declare class A {
    value: Pick<{
        __private: "d";
    } & import("../generated/types").TypeD, "__private" | "da" | "db" | "dc">;
}

Playground Link:
I couldn't figure out how to compile declarations in playground, sorry :(

As an alternative please clone the following repo: https://github.com/klemenoslaj/typescript-type-assertion

Explanation:
This is quite a significant problem in monorepo environment.
What happens is that projects are compiled in the dist/ folder and they contain relative path like above (import("../generated/types")), which points from the src/ and not from dist/, effectively producing an error when projects start using one another.

Why doesn't typescript:

  • use the original path from the import (generated/types)?
  • use the type from assertion directly (Model)?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Clone the linked repro repository and compile the files under src/ with declarations enabled, then compare dist/index.d.ts with the expected output. Start by tracing declaration generation for the assertion in src/index.ts and the Model type from src/index.model.ts. Done means the generated declaration preserves Model and uses an import path that remains valid from dist/.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.