Skip to content

有没有可能,让 .type.ts、.test.ts 这样的特殊后缀不再特殊? #59

@Gaubee

Description

@Gaubee

比如使用 .#type.ts.#test.ts,那么就可以沿用现有的“文件宏”的模式来进行项目生成。生成 tsconfig.type.jsontsconfig.test.json

在这两个案例中,#type 的特性是只包含 #type.ts 的文件。#test 的特性则是包含了其它正常的 normal.ts.#test.ts 文件。
这也就意味着文件宏其实是可以灵活配置它的includes的:

export default {
  profiles: {
    type: {
      includesMode: "strict",
    },
    test: {
      includesMode: "loose",
    },
  },
};

此外 #type 目前的版本是直接通过特殊的方式内建到类型定义模块中。
这里涉及到 #type 的设计,采用的是全局declare的形式。官方对于纯 esm 项目的态度,是一定程度上反对这种全局定义的做法的,但我们之所以坚持这样去做,有几点原因:

  1. 避免多次引入
    node_modules 出了名的依赖管理问题,而declare type这种全局定义,可以一定程度上间接地告知开发者,项目依赖中同时出现了多个版本。
    这种间接的利用这个“缺点”来规避更多的问题,看起来很蠢,但却为我们的项目管理提供了很好的依赖管理的保障,我们不会突然某一个版本编译出来的代码体积膨胀很多。我们不会莫名其妙地出现多个同名的 class 误导开发者(其实也是会有,因为只有declare type会冲突,declare interface则不会……,所以说只是“一定程度上”)

  2. 当下我们总会需要全局
    TypeScript/JavaScript 本身是一个脚本语言,在脚本语言的环境中,是没有任何“外部功能的”,所以可以看到在 esm 标准出来之前,几乎所有的 runtime,都是通过 globalThis 来托管这些外部功能。即便是 deno 这个遵循 esm 标准的也是如此,愿意无它,无非就是这种模式的抽象成本最低。
    不论如何我们总是需要全局,这不是我们自己项目能否做到独善其身的问题,而是整个大环境就是有全局定义这个玩意儿。所以官方不推荐用
    而我并不推荐使用module 'name' {},是因为觉得这样代码把node-module-name这概念绑死在一起,是一种错误的设计。module 'name' {}应该只用于针对性很强的场景,在正常的项目核心开发时,不该出现这种写法。

  3. 可以很清晰地隔离类型与实例
    因为类型的定义是没有成本的,所以带有namespace的代码,导致代码变长也不会有什么负担,只要能满足可读性、可维护性的需求,那它便是有价值的。
    虽然官方给出了import type,我们也可以通过以下这种写法来暴露类型:

    class MyClass {}
    export namespace MyClass {
      export type A = string;
    }

    虽然我自己也更加喜欢这种模式,但这种模式的有它局限性,详见下一点

  4. 我们需要可扩展的interface。在插件模式中,一个模块引入后从而使得原有的一个interface增加了它的属性。这种模式在开发时非常有用,但是 esm 强调隔离,所以是无法做到扩展的,这会给我们编码带来很多不便。这种牺牲,目前看来是一种倒退。

但是未来我们还是要去拥抱pure-esm,以上提到的问题,相信未来 typescript 社区也会提供响应的解决方案。比如说:

  1. 在语言服务器在优化import语句的时候,能够自动帮我重写import type
  2. import type的代码,在代码高亮的时候能用不同的样式区分到底是class 实例还是interface/type 类型
  3. 增加可扩展性的interface,比如:
    /// a.ts
    export open interface MyFace{}
    /// b.ts
    import type { MyFace } from "./a.ts"
    // reopen and declare
    open interface MyFace {
        fieldb: "B"
    }

虽然这些未来还很遥远,但我想pkgm能否做到将目前的偏见给灵活化,让.type.ts.test.ts的定义权益回到开发者手上?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions