类似vue-router 类型化路由,但是不通过外部插件,纯ts手段。
比如两个函数:
export function definePath<T extends string>(path: string)
export function getPath(): string
我想做到:
definePath('/a')
definePath('/b')
getPath() => '/a' | '/b'
其中definePath
可以在任何地方引入,无法收归到一个文件里。
能做到吗?
类似vue-router 类型化路由,但是不通过外部插件,纯ts手段。
比如两个函数:
export function definePath<T extends string>(path: string)
export function getPath(): string
我想做到:
definePath('/a')
definePath('/b')
getPath() => '/a' | '/b'
其中definePath
可以在任何地方引入,无法收归到一个文件里。
能做到吗?
在 TypeScript 中,实现一个可以动态扩充的类型声明并且达到你所描述的效果(即 getPath()
函数返回一个包含所有通过 definePath
添加的路径的联合类型),并不直接支持,因为 TypeScript 的类型系统本质上是静态的,在编译时确定类型。而你所希望实现的是运行时的动态行为影响编译时的类型,这在 TypeScript 中是一个挑战。
然而,可以通过一些技巧接近这个效果,但请注意,这些方法都有其局限性,并且通常涉及到全局变量或类型声明文件的修改,这在大型项目中可能不是最佳实践。
下面是一个可能的解决方案,使用全局类型变量和 TypeScript 的声明合并特性:
创建一个全局类型变量来收集路径:
首先,我们需要在全局作用域中定义一个类型,用于存储所有定义的路径。这可以通过在全局声明文件中(例如 global.d.ts
)定义一个接口来实现。
// global.d.ts
declare global {
interface PathRegistry {
paths: string[];
}
const _PathRegistry: PathRegistry;
}
export {}; // 确保这是一个模块文件
然后,在你的代码中,你需要确保这个全局变量被初始化(如果尚未初始化)。
// 在你的某个初始化代码中(例如 main.ts 或 app.ts)
if (!_PathRegistry) {
_PathRegistry = { paths: [] };
}
定义 definePath
和 getPath
函数:
接下来,我们定义 definePath
和 getPath
函数,并更新全局的路径注册表。
// path-manager.ts
import '_PathRegistry'; // 确保全局变量可用
type KnownPaths = _PathRegistry['paths'][number];
export function definePath<T extends string>(path: T) {
if (!_PathRegistry.paths.includes(path)) {
_PathRegistry.paths.push(path);
}
}
export function getPath<T extends KnownPaths>(path: T): T;
export function getPath(): KnownPaths;
export function getPath(path?: string): string {
if (path && _PathRegistry.paths.includes(path as string)) {
return path as KnownPaths;
}
// 注意:这里简单返回第一个路径作为示例,实际逻辑可能需要根据需求调整
return _PathRegistry.paths[0] as KnownPaths;
}
使用类型守卫或类型断言:
由于 TypeScript 无法在编译时自动推断 getPath()
的返回类型为所有定义路径的联合类型,你可能需要在使用 getPath()
时使用类型断言或类型守卫来确保类型安全。
definePath('/a');
definePath('/b');
const path = getPath(); // 类型为 string,但你知道它应该是 '/a' | '/b'
if (path === '/a' || path === '/b') {
// 这里的 path 被缩小为 '/a' | '/b'
}
注意:
_PathRegistry
,这在实际应用中可能不是最佳实践,特别是在大型项目中,因为它可能导致难以追踪的副作用和依赖。如果你的应用场景允许,考虑使用更静态的方法或工具来管理你的路径和类型。