typescript 使用ReadonlyMap〈K,V>类型

nvbavucw  于 2022-12-14  发布在  TypeScript
关注(0)|答案(2)|浏览(164)

TypeScript定义ReadonlyMap<K, V>接口,该接口是标准JavaScript Map<K, V>类型的不可变版本。
我们应该如何在代码中使用ReadonlyMap<K, V>
它不是从任何东西派生的,也没有声明构造函数。那么,我们是否应该:

public publicApiMethod(): ReadonlyMap<K, V> {
    const map: Map<K, V> = new Map(...);
    return map as ReadonlyMap<K, V>;
}

或者有更好的方法来使用ReadonlyMap<K, V>而不仅仅是类型转换?

8tntrjer

8tntrjer1#

简短回答:你做得很好。
ReadonlyMap<K, V>本质上是Map<K, V>的 * 超类型 *,因为它的方法和属性与Map<K,V>的方法和属性匹配。因此,通过将Map作为ReadonlyMap返回,您所做的只是扩展了值的类型。顺便说一下,这意味着您可以跳过类型Assert:

public publicApiMethod(): ReadonlyMap<K, V> {
    const map: Map<K, V> = new Map(...);
    return map; // no assertion necessary
}

就像你可以这样做:

public anotherMethod(): string | number {
    return "hey"; // always "hey", but assignable to string | number
}

这样做的好处是,调用方不能随意假定返回值具有任何其他Map方法,并且尝试设置或清除Map内容将产生编译时错误,尽管这些方法在运行时确实存在。(或者对于anotherMethod()示例,调用方无法知道返回值始终为string,也无法直接调用任何字符串特定的方法。)
这种编译时禁止运行时行为的方式类似于readonly修饰符的工作方式。当属性为readonly时,如果您试图修改它,TypeScript将报告错误,即使在运行时修改会成功。
如果你愿意,你可以实现你自己的ReadonlyMap版本,即使在运行时也是只读的,但是只有当你有一个需要它的用例时,这才是值得的。如果你不需要,(你可能不需要),那么不要担心,继续用你现在的方式去做。
希望能有所帮助;祝你好运!

xqk2d5yq

xqk2d5yq2#

为了在编译时感到安全,我们可以这样使用:

public publicApiMethod(): ReadonlyMap<K, V> {
    const map: Map<K, V> = new Map(...);
    ...
    return map; // no need casting
}

为了让自己在运行时感到安全,我们可以这样使用:

public publicApiMethod(): ReadonlyMap<K, V> {
    const map: Map<K, V> = new Map(...);
    ...

    const trueRuntimeReadonlyMap: ReadonlyMap<string, string> = Object.freeze({
        entries: attrs.entries.bind(attrs),
        forEach: attrs.forEach.bind(attrs),
        get: attrs.get.bind(attrs),
        has: attrs.has.bind(attrs),
        keys: attrs.keys.bind(attrs),
        size: attrs.size,
        values: attrs.values.bind(attrs),
        [Symbol.iterator]: attrs[Symbol.iterator].bind(attrs)
    });

    return trueRuntimeReadonlyMap;
}

相关问题