如何为这样的函数定义类型?

时间:2019-10-09 13:56:42

标签: typescript

我正在将一些代码移至TS,并且一直在努力为一组路由功能定义一种类型。它们就是这样的:

const root: Route = () => 'root'
root.child = () => `${root()}/child`
root.child.grandchild = () => `${root.child()}/grandchild`

我试图在嵌套属性的索引签名旁边定义某种递归可调用类型或接口,但没有成功:

type Route = {
  (): string
  [key: string]: Route
}

关于我该怎么做的任何想法或想法?

游乐场:http://www.typescriptlang.org/play/index.html?ssl=1&ssc=1&pln=10&pc=1#code/C4TwDgpgBASg9gV2NAvFA3gKCjqAKASgC4oBnYAJwEsA7Ac21wG0BrCEE86+gXRPiQRMAX0yYAxnBrkoFOHGD9EyKGkKqAfFADkchdsx7gAOnEALKgBsAJqvwFNUAAYASdEcLCA9OavWnhvImvjbGdBQAhjTWIbZqDiharu5BphY2nl7hUTHp-mJAA

1 个答案:

答案 0 :(得分:3)

根据您要尝试执行的操作,有几种选择。

如果您使用常规的function定义,则可以在声明该函数的范围内向该函数添加其他属性,TS会将这些属性识别为该函数的属性:

function root() { return 'root' }
function child() { return `${root()}/child` }
child.grandchild = () => `${root.child()}/grandchild`
root.child = child;



root.child.grandchild() //ok

Play

另一种选择是使用Object.assign一次性创建具有属性的函数:


const root = Object.assign(() => 'root', {
    child: Object.assign(() => `${root()}/child`, {
        grandchild: () => `${root.child()}/grandchild`
    })
});

root.child.grandchild()

Play

这两个选项实际上都不使用您的Router接口,该接口允许以后添加任何字符串属性。为此,我认为最简单的选择是创建一个将在内部使用Object.assign但也将使用所需类型的辅助函数:

type Route = {
    (): string
    [key: string]: Route
}

function createRoute(fn: () => string, other: Record<string, Route> = {}) {
    return Object.assign(fn, other);
}

const root: Route = createRoute(() => 'root', {
    child: createRoute(() => `${root()}/child`, {
        grandchild: createRoute(() => `${root.child()}/grandchild`)
    })
})

Play