在Typescript中模拟私有继承的最佳方法是什么?具体而言,chid类要隐藏父类的某些成员。

例如,预期的解决方法应达到以下目的:

CustomArray<T>Array<T>扩展,并隐藏仅说pop()shift()的特定成员。

let c1 = new CustomArray<number>();
c1.push(10, 20, 30, 40, 50); // okay
c1.shift(); // should error
c1.pop();   // should error
c1.sort(); // okay  etc...


这是我尝试过的方法,但是vscode仍然允许应该是受限成员。

//Try to hide pop() and push():
type T1<T> = Exclude<Array<T>, 'pop'| 'push'>

// check
let x: T1<number> = [];
x.push(3);  // allowed -- okay
x.pop();    // also allowed -- but wanted it to be an error

最佳答案

您不希望使用继承,因为您不打算允许使用CustomArray<T>的所有相同方式使用Array<T>

您可以做的是将新类型定义为Array<T>的函数,并使CustomArray构造函数与Array构造函数在运行时相同:

type CustomArray<T> = Pick<Array<T>, Exclude<keyof Array<T>, "shift" | "pop">>;
const CustomArray: new <T>() => CustomArray<T> = Array;

let c1 = new CustomArray<number>();
c1.push(10, 20, 30, 40, 50); // okay
c1.shift(); // error
c1.pop();   // error
c1.sort(); // okay


这就是您要求的方式。但是请记住,这是Array<T>的“浅”转换。例如,sort()方法仍将返回Array<T>,而不是CustomArray<T>

c1.sort().pop(); // okay


如果您确实想进行“深层”转换,用Array<T>替换所有与CustomArray<T>有关的内容,则可能需要继续并手动指定完整接口,因为自动映射不太可能按您希望的方式工作:

interface CustomArray<T> {
  length: number;
  toString(): string;
  toLocaleString(): string;
  // pop(): T | undefined;
  push(...items: T[]): number;
  concat(...items: ConcatArray<T>[]): CustomArray<T>;
  concat(...items: (T | ConcatArray<T>)[]): CustomArray<T>;
  join(separator?: string): string;
  reverse(): CustomArray<T>;
  // shift(): T | undefined;
  slice(start?: number, end?: number): CustomArray<T>;
  sort(compareFn?: (a: T, b: T) => number): this;
  // ... ALL the other methods, omitted for brevity
}
const CustomArray: new <T>() => CustomArray<T> = Array;
const c1 = new CustomArray();
c1.push(10, 20, 30, 40, 50); // okay
c1.shift(); // error
c1.pop();   // error
c1.sort(); // okay
c1.sort().pop(); // error


这比较麻烦,但是您可以对结果进行更多控制。不管哪种方法对您都有效。希望能有所帮助;祝好运!

07-23 08:11