用 typescript 无限修改

k5ifujac  于 2023-01-31  发布在  TypeScript
关注(0)|答案(1)|浏览(154)

我做了下面的代码实现无限currying的路径连接。

function joinPath(): string
function joinPath(a: string): typeof joinPath
function joinPath(a?: string): string | typeof joinPath {
  if (a === undefined) { return '' }
  const func = (b?: string) => {
    if (b === undefined) { return a }
    return joinPath(`${a}/${b}`)
  }

  return func as typeof joinPath
}

console.log(joinPath('www.github.com')()) // www.github.com
console.log(joinPath('www.github.com')('react')) // www.github.com/react

joinPath的结果不是文本类型,而是字符串类型。
例如joinPath('facebook')(): string // not 'facebook'
我怎样才能使结果为文本类型呢?看来我必须使用泛型类型,但是我找不到工作的方法。
我尝试使用泛型类型将结果类型设置为文本,但没有成功。

7hiiyaii

7hiiyaii1#

为了跟踪字符串的字面类型,你需要joinPath的类型本身是generic,因为用另一个字符串调用结果函数会产生修改那个字符串的效果,你会希望joinPath的类型是一个递归的泛型类型,最简单的方法是使用一个命名的接口,比如:

interface JoinPath<T extends string> {
  (): T;
  <U extends string>(a: U): JoinPath<`${T}/${U}`>
}

所以JoinPath<T>保留字符串类型T,如果不带参数调用它,结果是T,否则,如果带泛型类型U的参数调用它,结果是string,这里我们使用template literal type来表示TU的串联。
现在您可以如下所示注解重载调用签名:

function joinPath(): ""
function joinPath<U extends string>(a: U): JoinPath<U>
function joinPath(a?: string) {
  if (a === undefined) { return '' }
  const func = (b?: string) => {
    if (b === undefined) { return a }
    return joinPath(`${a}/${b}`)
  }
  return func
}

因此joinPath()返回空字符串"" , otherwise joinPath(a)returns JoinPath "。
让我们来测试一下:

const w = joinPath();
// const w: ""
console.log(w); // ""

const f = joinPath('www.github.com');
// const f: JoinPath<"www.github.com">

const x = f();
// const x: "www.github.com"
console.log(x); // www.github.com

const g = f("react");
// const g: JoinPath<"www.github.com/react">

const y = g();
// const y: "www.github.com/react"
console.log(y); //  "www.github.com/react" 

const h = g("foobar");
// const h: JoinPath<"www.github.com/react/foobar">
const z = h();
// const z: "www.github.com/react/foobar"
console.log(z); // "www.github.com/react/foobar"

看起来不错。在所有情况下变量的类型和变量的值都一致。
Playground代码链接

相关问题