繁体   English   中英

TypeScript通用参数类型扩展另一种类型

[英]TypeScript Generic Parameter Type Extending Another Type

我在编译以下内容时遇到问题。 它包含在一个旧项目中,带有注释-“这是TS1.8功能。保留它以确保环境运行正确的ts”。

  function assign<T extends U, U>(target: T, source: U): T {
        for (let id in source) {
            target[id] = source[id]; // error TS2322: Type 'U[Extract<keyof U, string>]' is not assignable to type 'T[Extract<keyof U, string>]'.
        } 
        return target;
    }

我正在使用以下命令进行编译

tsc -p tsconfig.json

而这个tsconfig.json

{
  "include": [
    "Scripts/TypeScripts/**/*"
  ],
  "compilerOptions": {
    "target": "es5",
    "module": "amd",
    "sourceMap": false,
    "watch": false
  }
}

tsc -v产生Version 3.4.5

在操场上尝试时 ,我还会看到错误,这使我认为它确实是无效的代码。 但是,这提出了一个问题,当我写此评论时我在想什么,以及它为什么已经编译了两年(或已经编译了??)

所以-我的问题:这是有效的TS代码吗? 如果没有,那曾经吗?

谢谢 :-)

这对我来说似乎无效,但是我没有使用TS1.8(我想我从2.4左右开始)。 使用T extends U的问题在于,虽然U的所有属性键也必须存在于T ,但这些属性键上的可能更窄 也就是说,鉴于此:

function badAssign<T extends U, U>(target: T, source: U): T {
  for (let id in source) {
    target[id] = source[id] as any; // assert to remove error, but
  }
  return target;
}

你可以这样做:

interface Ewe {
  w: string;
  x: number;
  y: boolean;
}
interface Tee extends Ewe {
  w: "hey";
  x: 1;
  y: true;
  z: object;
}

const t: Tee = { w: "hey", x: 1, y: true, z: {} };
const u: Ewe = { w: "you", x: 2, y: false };
const newT = badAssign(t, u); // compiles, but
newT.w // "hey" at compile time, "you" at runtime !! 
newT.x // 1 at compile time, 2 at runtime !!
newT.y // true at compile time, false at runtime !!

这是很糟糕......通过指定source[id]target[id]您所假定属性类型的target[id] 相同或比类型更广泛的 source[id]但是当T extends U意味着相反: target[id]source[id]的类型相同或更窄 因此,您已经对编译器撒谎了。

我要解决此问题的方法是,用一些扩展了keyof T KPick<T, K>替换U 这样可以确保target每个键都像以前一样存在于source ,此外,还可以确保对target每个键,可以将source的相应属性的值分配给它:

function assign<T, K extends keyof T>(target: T, source: Pick<T, K>): T {
  for (let id in source) {
    target[id] = source[id]; // okay
  }
  return target;
}

这捕获了错误调用的错误:

assign(t, u); // now an error, string is not assignable to "hey"

但是仍然可以让您按预期使用assign()

let target = { a: "hey", b: 123, c: true };
let source = { a: "you", c: false };
const ret = assign(target, source);

好的,希望能有所帮助; 祝好运!

链接到代码

我猜想如果使用TypeScript <v1.8,则将其插入以作为引发错误的保护措施。

通过“ v1.8的TypeScript新增功能”小节“将类型参数作为约束 ”:

使用TypeScript 1.8,类型参数约束可以从同一类型参数列表中引用类型参数。 以前这是一个错误。 此功能通常称为F界多态性。

Example
function assign<T extends U, U>(target: T, source: U): T {
    for (let id in source) {
        target[id] = source[id];
    }
    return target;
}

let x = { a: 1, b: 2, c: 3, d: 4 };
assign(x, { b: 10, d: 20 });
assign(x, { e: 0 });  // Error

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM