使用 TypeScript 可以实现以下功能吗?
const mod = await import('./path/to/module')
// Is it possible to implement a utility type "ImportPath" that extracts
// the import path? Here the type of modImportPath would be './path/to/module'.
type modImportPath = ImportPath<typeof mod>
Run Code Online (Sandbox Code Playgroud)
我是vite-plugin-ssr的作者,我希望能够从以下内容推断页面 ID。
// The vite-plugin-ssr user provides the app's routes
const routes = [
{
// How to infer the page's ID `LandingPage` from this dynamic import?
Page: () => import('./pages/LandingPage'),
route: '/'
},
{
// How to infer the page's ID `AboutPage` from this dynamic import?
Page: () => import('./pages/AboutPage'),
route: '/about'
}
]
Run Code Online (Sandbox Code Playgroud)
至少有 3 种不同的方法来实现此功能,但没有一种方法是完美的
declare const RawImportPath: unique symbol;
declare const PageId: unique symbol;
type SplitOffStart<T, V extends string> = T extends `${string}${V}${infer E}` ? E : T;
type SplitOffEnd<T, V extends string> = T extends `${infer E}${V}${string}` ? E : T;
type SplitGetLast<T, V extends string> = T extends `${string}${V}${infer E}` ? SplitGetLast<E, V> : T;
type GetName<Path extends string> = SplitOffEnd<SplitGetLast<Path, '/' | '\\'>, '.vue'>
function myImport<T extends string>(path: T) {
let v = import(path)
return v as typeof v & { [RawImportPath]: T, [PageId]: GetName<T> }
// or `return v as Promise<{ [RawImportPath]: T, [PageId]: GetName<T>}>`
// (`any` should be excluded as it would void types)
}
function addType<T extends string>() {
// double-function is somewhat dirty but I don't know a better way
return <V>(v: V) => v as V & { [RawImportPath]: T, [PageId]: GetName<T> }
}
type Imported<T extends string> = { [RawImportPath]: T, [PageId]: GetName<T> } & Promise<any>
const routes = [
{
/**
* The import safety(file exists) typecheck is lost
* The import suggestions are lost
* Module type is lost
* (property) Page: () => Promise<any> & {
* [RawImportPath]: "./pages/LandingPage.vue";
* [PageId]: "LandingPage";
* }
*/
Page: () => myImport('./pages/LandingPage.vue'),
route: '/'
},
{
/**
* Looks dirty
* No string sameness typecheck
* (property) Page: () => Promise<typeof import('./pages/AboutPage')> & {
* [RawImportPath]: "./pages/AboutPage";
* [PageId]: "AboutPage";
* }
*/
Page: () => addType<'./pages/AboutPage'>()(import('./pages/AboutPage')),
route: '/about'
},
{
/**
* No string sameness typecheck
* Module type is lost
* (property) Page: () => Promise<any> & {
* [RawImportPath]: "./pages/AboutPage";
* [PageId]: "AboutPage";
* }
*/
Page: () => import('./pages/ThirdPage') as Imported<'./pages/ThirdPage'>,
route: '/about'
}
]
Run Code Online (Sandbox Code Playgroud)
更好的方法被https://github.com/microsoft/TypeScript/issues/32705阻止
| 归档时间: |
|
| 查看次数: |
319 次 |
| 最近记录: |