打字稿。如何使用未导出的类型定义?

TypeScript. How to use not exported type definitions?

看看这个打字稿代码:


lib.ts

interface Human {
    name: string;
    age: number;
}

export default class HumanFactory {
    getHuman(): Human {
        return {
            name: "John",
            age: 22,
        }
    }
}

index.ts

import HumanFactory from "./lib";

export class Foo {
    human: any;

    constructor() {
        const factory = new HumanFactory();
        this.human = factory.getHuman();
    }

    diffWithError(age: number): number {
        return age - this.human.name;
    }

    diffWithTypingAndAutocoplete(age: number): number {
        const factory = new HumanFactory();
        return age - factory.getHuman().name;
    }
}

"human" 属性 "Foo" class 中的问题。我无法将此变量的类型定义为来自 lib.ts.

的 "Human" 接口

在方法"diffWithError"中我犯了一个错误——在算术运算中使用了数字"age"和字符串"name",但是IDE和ts编译器都不知道这个,因为在这种情况下,"this.human.name" 的类型是 "any"

在方法"diffWithTypingAndAutocoplete"中我只使用了方法"getHuman"。 IDE 并且编译器知道方法结果的类型。这是 "Human" 界面和字段 "name" 是 "string"。此方法在编译源代码时会触发错误。


我在尝试导入 JS 库的 .d.ts 文件时发现了这个问题,但我无法导出所需的接口。每当我想定义类型(并且没有内联类型定义,如 { name: string, age:数字 })。

我不想创建未导出的 classes 的实例,我只想要类型检查和自动完成。


P.S。我试着写这个:

human: Human

编译器触发错误:"error TS2304: Cannot find name 'Human'"(预期行为)


P.S.S 我尝试使用三重斜杠指令来做到这一点:

///<reference path="./lib.ts" />

但这也行不通。


抱歉我的英语不好,感谢您的回答

您需要导出 Human 以便它在 index.ts 中可见并可用(如 HumanFactory)。不要使用默认导出,而是 "named exports" 即试试这个

export interface Human {
    name: string;
    age: number;
}

export class HumanFactory {
    getHuman(): Human {
        return {
            name: "John",
            age: 22,
        }
    }
}

index.ts

import { Human, HumanFactory} from "./lib";

** 编辑 **

如果您无法更改 lib.d.ts,则重新定义 Human 并使用双重转换,即

import HumanFactory from "./lib";

interface Human {
    name: string;
    age: number;
}

export class Foo {
    human: Human;  // <= change here

    constructor() {
        const factory = new HumanFactory();
        this.human = factory.getHuman() as any as Human;  // <= double casting 
    }

    diffWithError(age: number): number {
        return age - this.human.name;
    }

    diffWithTypingAndAutocoplete(age: number): number {
        const factory = new HumanFactory();
        return age - factory.getHuman().name;
    }
}

更新

现在有了 conditional types 就可以在没有解决方法的情况下完成:

type Human = ReturnType<HumanFactory['getHuman']>

解决方法 TS < 2.8

如果您无法更改 lib.ts,您可以 "query" return 类型的 getHuman 函数。这有点棘手,因为打字稿目前没有为此提供任何直接的方法:

import HumanFactory from "./lib";

const dummyHuman = !true && new HumanFactory().getHuman();
type Human = typeof dummyHuman;

export class Foo {
  human: Human;

  // ...
}

!true &&用于防止new HumanFactory().getHuman()执行。

我找到了解决办法!

我制作文件 human-interface.ts 内容如下:

import HumanFactory from './lib';

const humanObject = new HumanFactory().getHuman();
type HumanType = typeof humanObject;

export default interface Human extends HumanType {}

在主文件中导入此接口不会执行创建 "HumanFactory" 并且类型检查工作正常。

感谢 typeof

的想法

在 TypeScript 2.8 中引入了 ReturnType<> 静态类型,这变得更容易了。

import HumanFactory from "./lib";
type Human = ReturnType<typeof HumanFactory.prototype.getHuman>

另见