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

.d.ts files strip private property types, which can be used to distinguish instance types #38953

Closed
tjjfvi opened this issue Jun 5, 2020 · 6 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@tjjfvi
Copy link
Contributor

tjjfvi commented Jun 5, 2020

TypeScript Version: 4.0.0-dev.20200604

Search Terms:
private class property type declaration

Expected behavior: .d.ts files preserve the types of private properties, as these determine if an instance type is assignable to another

Actual behavior: .d.ts files strip private property type, creating an error

Related Issues: N/A

Code

namespace Original {
    class Box<T> {
        declare private value: T;
    }

    type Assert<T, U extends T> = U;

    export type False = Assert<false, Box<number> extends Box<string> ? true : false>;
}

// Compiles to:

declare namespace Compiled {
    class Box<T> {
        private value;
    }
    type Assert<T, U extends T> = U;
    // Errors becuase the type of Box.value was stripped
    export type False = Assert<false, Box<number> extends Box<string> ? true : false>;
    export {};
}

Obviously, this is a contrived example, but this was an issue I ran into.

Output
"use strict";
var Original;
(function (Original) {
    class Box {
    }
})(Original || (Original = {}));
Compiler Options
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "moduleResolution": 2,
    "target": "ES2017",
    "jsx": "React",
    "module": "ESNext"
  }
}

Playground Link: Provided

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Jun 5, 2020
@RyanCavanaugh
Copy link
Member

Removing the types is necessary for compatibility/implementation-hiding reasons. The correct fix would be for us to emit the variance measurement of T in the .d.ts; see #1394

@tjjfvi
Copy link
Contributor Author

tjjfvi commented Jun 25, 2020

A workaround is to use protected instead of private; it will preserve the type in the .d.ts, while still keeping it nominal.

@tjjfvi
Copy link
Contributor Author

tjjfvi commented Oct 22, 2020

What if the compiler outputted (variance: any) => any, (variance: any) => T, (variance: T) => any, or (variance: T) => T (multiple generics can be handled with intersections, i.e. (variance: T & U) => U), based on the variance. When #1394 lands, it could be changed to the corresponding types, which wouldn't be a breaking change, as the types of private properties are not relevant for anything.

@ostrowr
Copy link

ostrowr commented Oct 27, 2020

This leads to confusing behavior where vscode (or your editor of choice) reports errors that the compiler doesn't catch when using project references.

E.g. in this playground the editor can infer the type of x even though it's private. If you've set up vscode with project references, the types will be read from the .ts files rather than the .d.ts files, which means the editor can get the type of x.

However, if the type is imported via a .d.ts file (i.e. at compile time), the type of x is any! This leads to a long path of debugging where you can't figure out why vscode doesn't match tsc.

Given that it seems we can't annotate private members with their types, it would probably make sense to explicitly forbid using types of private members imported from .d.ts files.

@pilcrowonpaper
Copy link

2 years later and ran exactly into this issue

However, if the type is imported via a .d.ts file (i.e. at compile time), the type of x is any! This leads to a long path of debugging where you can't figure out why vscode doesn't match tsc.

Would like to clarifications inside docs on protected vs private and/or remove the ability to get types from private methods entirely.

@Stono
Copy link

Stono commented Jul 18, 2024

2 years later, exactly the same rabbithole and just stumbled across this 🤣

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

5 participants