简体   繁体   English

TypeScript:具有泛型的递归深度可变。 错误:T 不可分配给 Mutable<T>

[英]TypeScript: Recursive Deep Mutable with Generics. Error: T is not assignable to Mutable<T>

I'm trying to write a deep recursive Mutable type:我正在尝试编写一个深度递归的Mutable类型:

Mutable<T> = ...
    // remove all "readonly" modifiers
    // convert all ReadonlyArray to Array
    // etc.
    // and do it all recursively

const mutate = <T>(val: T, mutateFn: (mutableVal: Mutable<T>) => void): T => {
  return null as any
}

It's working fine as long as I don't use generics:只要我不使用泛型,它就可以正常工作:

// works fine
mutate([] as ReadonlyArray<string>, mutableVal => {
  mutableVal.splice(42, 0, "test");
});

But when using it within a generic function I get an error:但是在通用函数中使用它时出现错误:

// Error: Argument of type 'T' is not assignable to parameter of type 'Mutable<T>'.
const doSomething = <T>(array: ReadonlyArray<T>, index: number, elem: T) => {
  mutate(array, mutableVal => {
                      // Here's the error
                      //         v
    mutableVal.splice(index, 0, elem);
  });
}

I understand, that the mutable array's type is Array<Mutable<T>> , and that splice now expects a Mutable<T> value, instead of T .我知道,可变数组的类型是Array<Mutable<T>> ,并且splice现在需要一个Mutable<T>值,而不是T But I can't figure out how to solve it.但我不知道如何解决它。

Do you have any idea how to solve this?你知道如何解决这个问题吗?

I've created a TypeScript Playground, so you can play with the code: Link to TypeScript Playground我创建了一个 TypeScript Playground,因此您可以使用以下代码: Link to TypeScript Playground

My suggestion is to do something like this:我的建议是做这样的事情:

const doSomething = <T>(array: ReadonlyArray<T>, index: number, elem: T) => {
    mutate({ array: array, elem: elem }, mutableVal => {
        mutableVal.array.splice(index, 0, mutableVal.elem);
    });
}

The idea is that you need elem to be mutable in order to add it to a deep-mutable array, but your original call was not doing that.这个想法是你需要elem是可变的,以便将它添加到一个深度可变的数组中,但你最初的调用并没有这样做。 Since you want to mutate both array and possibly elem , the most straightforward solution is to pass in an object containing both array and elem , and operate on the deep-mutable version of that.由于您想同时改变array和可能的elem ,最直接的解决方案是传入一个包含arrayelem的对象,并对其进行深度可变版本的操作。

Only you know if it's acceptable to call mutate() on elem as well as on array , since the implementation of mutate() is left out.只有您知道在elemarray上调用mutate()是否可以接受,因为mutate()的实现被忽略了。 I'm guessing it's going to be something involving an assertion like this:我猜这将涉及这样的断言:

const mutate = <T>(val: T, mutateFn: (mutableVal: Mutable<T>) => void): T => {
    mutateFn(val as Mutable<T>); //🤷‍♀️
    return val;
}

in which case I'd say "who cares" whether you call mutate() on elem , or whether you just assert elem to its mutable counterpart inside doSomething() .在这种情况下,我会说“谁在乎”你是否在elem上调用mutate() ,或者你是否只是将elem断言到它在doSomething()中的可变对应物。 On the other hand, if your implementation is something fancier involving cloning, then you should think about whether it makes sense to call it on elem or not.另一方面,如果您的实现是涉及克隆的更高级的东西,那么您应该考虑在elem上调用它是否有意义。

Okay, hope that helps.好的,希望有帮助。 Good luck!祝你好运!

Using DeepNonNullable from utility-types as inspiration and 99% of the code I came up with this:使用来自实用程序类型的 DeepNonNullable 作为灵感和 99% 的代码我想出了这个:

import { Mutable } from 'utility-types';

export type DeepMutable<T> = T extends (...args: any[]) => any
  ? T
  : T extends any[]
  ? DeepMutableArray<T[number]>
  : T extends object
  ? DeepMutableObject<T>
  : T;
/** @private */
export type DeepMutableArray<T> = Array<DeepMutable<Mutable<T>>>;
/** @private */
export declare type DeepMutableObject<T> = {
  [P in keyof T]-?: DeepMutable<Mutable<T[P]>>;
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 打字稿泛型:不可分配给T型 - Typescript generics : not assignable to type T 打字稿泛型。 无法将B的实例传递给参数a:T,其中T扩展了B。为什么? - Typescript generics. Can't pass instance of B to a argument a: T where T extends B. Why? TypeScript泛型:“类型不可分配给类型T” - TypeScript Generics: 'type is not assignable to type T' TypeScript 泛型 TypedArray:TypedArray 不可分配给 T - TypeScript Generics TypedArray: TypedArray is not assignable to T Typescript Generics 和不可分配错误 - Typescript Generics and not assignable error TypeScript Generics 问题:类型 T(扩展类型)不可分配给 T - TypeScript Generics problem: type T (extends Type) is not assignable to T React.js TypeScript(泛型)- 类型“T”不可分配给类型“ReactNode” - React.js TypeScript (Generics) - Type 'T' is not assignable to type 'ReactNode' TypeScript泛型类型“ {result:true}”不能分配给类型“ T” - TypeScript Generics type '{ result: true }' is not assignable to type 'T' 打字稿泛型:类型“ X”的参数不能分配给类型“ T”的参数 - Typescript generics: Argument of type 'X' is not assignable to parameter of type 'T' 打字稿编译错误:类型“ {}”不可分配给类型“ T” - Typescript Compile Error: Type '{}' is not assignable to type 'T'
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM