Skip to content

Unexpected type assertion result #32653

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)?

Activity

  1. dragomirtitian commented on Aug 1, 2019

    @dragomirtitian
    Contributor

    A generally feature of type aliases is that they can be expanded transparently by the compiler, so probably when you use the assertion the compiler does not think it needs to keep the name around.

    Using an interface will probably get you the effect you desire:

    export interface Model extends  Pick<DType, keyof Exclude<DType, '__private'>> {}
  2. klemenoslaj commented on Aug 1, 2019

    @klemenoslaj
    Author

    A generally feature of type aliases is that they can be expanded transparently by the compiler, so probably when you use the assertion the compiler does not think it needs to keep the name around.

    Using an interface will probably get you the effect you desire:

    export interface Model extends  Pick<DType, keyof Exclude<DType, '__private'>> {}

    Yes, that works 👍

    However, we cannot force people to use interfaces, therefore issue might still pop out causing frustrations, since it is not really straight forward problem.

    Is there any other way?

    EDIT

    Furthermore, if types are generated by 3rd party, we are even out of control, and using the type directly from generated/types will result in the same problem.

    I have update the repository accordingly:

    export class A {
        value1 = <Model>{};
        value2 = <Test['e']>{};
    }

    Results in

    export declare class A {
        value1: Pick<{
            __private: "d";
        } & import("../generated/types").TypeD, "__private" | "da" | "db" | "dc">;
        value2: {
            __private: "e";
        } & import("../generated/types").TypeD;
    }
  3. added
    Needs InvestigationThis issue needs a team member to investigate its status.
    and removed
    BugA bug in TypeScript
    on Jan 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs InvestigationThis issue needs a team member to investigate its status.

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions