打字稿替换对象键和值的通用

时间:2020-07-25 02:19:25

标签: typescript generics generic-programming typescript-generics

我有几个看起来像这样的代码块。有没有更好的方法可以通过泛型或其他打字稿功能来做到这一点?

    const { authors } = book
    
    if (authors?.author) {
      if (Array.isArray(authors.author)) {
        book.authors = authors.author
      } else {
        book.authors = [authors.author]
      }
    }

    const { bookLinks } = book
    
    if (bookLinks?.bookLink) {
      if (Array.isArray(bookLinks.bookLink)) {
        book.bookLinks = bookLinks.bookLink
      } else {
        book.bookLinks = [bookLinks.bookLink]
      }
    }

我想在上面的代码中创建一个使用两个参数(例如('authors', 'author')('bookLinks', 'bookLink'))的函数并替换变量。

1 个答案:

答案 0 :(得分:1)

我不确定100%是否遵循用例,但也许您的功能可能如下所示:

function fixBook<K extends PropertyKey>(
    book: any, key: K, subKey: PropertyKey
): asserts book is { [P in K]?: unknown[] } {
    if (!book) throw new Error("This is not an object"); 
    const { [key]: prop } = book;
    if (prop?.[subKey]) {
        if (Array.isArray(prop[subKey])) {
            book[key] = prop[subKey];
        } else {
            book[key] = [prop[subKey]];
        }
    } 
}

这与您上面的代码类似。它是assertion function,表示调用它之后,它将缩小输入对象的类型,以便您可以访问其属性。

示例:

const book: unknown = {
    authors: { author: "A" },
    bookLinks: { bookLink: ["b", "c"] }
}

这里我们有book类型的unknown ...带注释的unknown使编译器忘记了实际的类型,因此这应该复制您得到{{1} },并且不知道它是什么类型:

book

现在,我们两次致电book.authors.author; // error! object is of type unknown 。首先:

fixBook()

在该语句之后,fixBook(book, "authors", "author"); 的范围从book缩小到unknown 。 (请注意,它不是{authors?: unknown[]},因为编译器不知道{authors: string[]}是什么类型。按照不同的代码路径,我认为在运行函数后,特定属性要么是{{1 }}或一些未知类型的数组。)然后:

book?.authors?.author

该语句之后,undefined的范围进一步缩小到fixBook(book, "bookLinks", "bookLink"); 。我们可以通过访问book{authors?: unknown[]} & {bookLinks?: unknown[]}属性进行验证:

authors

看起来很合理。


好的,希望能为您提供一些指导;祝你好运!

Playground link to code