Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript:根据对象中的属性确定对象类型';s属性_Typescript_Discriminated Union_Conditional Types - Fatal编程技术网

Typescript:根据对象中的属性确定对象类型';s属性

Typescript:根据对象中的属性确定对象类型';s属性,typescript,discriminated-union,conditional-types,Typescript,Discriminated Union,Conditional Types,我可能对Typescript要求太多,但我想知道这样的事情是否可能: interface ObjectType { type: 'this' | 'that'; } interface SomeObject { objType: ObjectType } interface ThisObject extends SomeObject { objType: { type: 'this' } thisProp: 'anything' } interface Th

我可能对Typescript要求太多,但我想知道这样的事情是否可能:

interface ObjectType {
    type: 'this' | 'that';
}

interface SomeObject {
    objType: ObjectType
}

interface ThisObject extends SomeObject {
    objType: { type: 'this' }
    thisProp: 'anything'
}

interface ThatObject extends SomeObject {
    objType: { type: 'that' }; 
    thatProp: 'something'
}

function getProp(obj: ThisObject | ThatObject) {
    switch (obj.objType.type) {
        case 'this':
            return {
                type: obj.objType.type,
                prop: obj.thisProp
            };
        case 'that':
            return {
                type: obj.objType.type,
                prop: obj.thatProp
            };
    }
}
Typescript能够正确地缩小
obj.objType.type
,但是我试图在返回的对象中分配给
prop
的值不会进行类型检查。两者的错误相同(显然属性名称不同):

这样的事情可能吗?我也试过这样的方法:

interface SomeObject {
    objType: ObjectType;
    thisProp: SomeObject['objType'] extends 'this' ? 'anything' : never;
    thatProp: SomeObject['objType'] extends 'that' ? 'something' : never;
}
type PickObject<T> = T extends 'this' ? ThisObject : ThatObject;

function getProp<T extends 'this' | 'that'>(obj: PickObject<T>) {
    switch (obj.objType.type) {
        case 'this':
            return {
                type: obj.objType.type,
                prop: obj.thisProp
            };
        case 'that':
            return {
                type: obj.objType.type,
                prop: obj.thatProp
            };
    }
}
interface ThisObject extends SomeObject { objType: { type: 'this' }; thisProp: 'anything' }
interface ThatObject extends SomeObject { objType: { type: 'that' }; thatProp: 'something' }
function nestedDiscrim<T extends object | PropertyKey, D extends object | PropertyKey>(
  val: T, discriminant: D): val is Extract<T, D>;
function nestedDiscrim(val: any, discriminant: any) {
  if ((typeof val === "object") && (typeof discriminant === "object")) {
    for (let k in discriminant) {
      if (!(k in val)) return false;
      if (!nestedDiscrim(val[k], discriminant[k])) return false;
    }
    return true;
  }
  if ((typeof val !== "object") && (typeof discriminant !== "object")) {
    return val === discriminant;
  }
  return false;
}
function getProp(obj: ThisObject | ThatObject) {
  if (nestedDiscrim(obj, { objType: { type: "this" } } as const)) {
    return {
      type: obj.objType.type,
      prop: obj.thisProp
    };
  } else {
    return {
      type: obj.objType.type,
      prop: obj.thatProp
    };
  }
}
这导致这两种道具都是
从不
,以及类似的东西:

interface SomeObject {
    objType: ObjectType;
    thisProp: SomeObject['objType'] extends 'this' ? 'anything' : never;
    thatProp: SomeObject['objType'] extends 'that' ? 'something' : never;
}
type PickObject<T> = T extends 'this' ? ThisObject : ThatObject;

function getProp<T extends 'this' | 'that'>(obj: PickObject<T>) {
    switch (obj.objType.type) {
        case 'this':
            return {
                type: obj.objType.type,
                prop: obj.thisProp
            };
        case 'that':
            return {
                type: obj.objType.type,
                prop: obj.thatProp
            };
    }
}
interface ThisObject extends SomeObject { objType: { type: 'this' }; thisProp: 'anything' }
interface ThatObject extends SomeObject { objType: { type: 'that' }; thatProp: 'something' }
function nestedDiscrim<T extends object | PropertyKey, D extends object | PropertyKey>(
  val: T, discriminant: D): val is Extract<T, D>;
function nestedDiscrim(val: any, discriminant: any) {
  if ((typeof val === "object") && (typeof discriminant === "object")) {
    for (let k in discriminant) {
      if (!(k in val)) return false;
      if (!nestedDiscrim(val[k], discriminant[k])) return false;
    }
    return true;
  }
  if ((typeof val !== "object") && (typeof discriminant !== "object")) {
    return val === discriminant;
  }
  return false;
}
function getProp(obj: ThisObject | ThatObject) {
  if (nestedDiscrim(obj, { objType: { type: "this" } } as const)) {
    return {
      type: obj.objType.type,
      prop: obj.thisProp
    };
  } else {
    return {
      type: obj.objType.type,
      prop: obj.thatProp
    };
  }
}

似乎不需要
SomeObject
接口。下面是一个可能的解决方案,消除了
SomeObject
接口:


问题是
ObjectType
objType
objType
实际上并不定义接口的类型。以下是一个工作示例:

type ObjectType = 'this' | 'that'

interface SomeObject {
  type: ObjectType
}

interface ThisObject extends SomeObject {
  type: 'this'
  thisProp: 'anything'
}

interface ThatObject extends SomeObject {
  type: 'that'
  thatProp: 'something'
}

function getProp(obj: ThisObject | ThatObject) {
  switch (obj.type) {
    case 'this':
      return {
        type: obj.type,
        prop: obj.thisProp
      };
    case 'that':
      return {
        type: obj.type,
        prop: obj.thatProp
      };
  }
}

假设您的类型实际上是这样的:

interface SomeObject {
    objType: ObjectType;
    thisProp: SomeObject['objType'] extends 'this' ? 'anything' : never;
    thatProp: SomeObject['objType'] extends 'that' ? 'something' : never;
}
type PickObject<T> = T extends 'this' ? ThisObject : ThatObject;

function getProp<T extends 'this' | 'that'>(obj: PickObject<T>) {
    switch (obj.objType.type) {
        case 'this':
            return {
                type: obj.objType.type,
                prop: obj.thisProp
            };
        case 'that':
            return {
                type: obj.objType.type,
                prop: obj.thatProp
            };
    }
}
interface ThisObject extends SomeObject { objType: { type: 'this' }; thisProp: 'anything' }
interface ThatObject extends SomeObject { objType: { type: 'that' }; thatProp: 'something' }
function nestedDiscrim<T extends object | PropertyKey, D extends object | PropertyKey>(
  val: T, discriminant: D): val is Extract<T, D>;
function nestedDiscrim(val: any, discriminant: any) {
  if ((typeof val === "object") && (typeof discriminant === "object")) {
    for (let k in discriminant) {
      if (!(k in val)) return false;
      if (!nestedDiscrim(val[k], discriminant[k])) return false;
    }
    return true;
  }
  if ((typeof val !== "object") && (typeof discriminant !== "object")) {
    return val === discriminant;
  }
  return false;
}
function getProp(obj: ThisObject | ThatObject) {
  if (nestedDiscrim(obj, { objType: { type: "this" } } as const)) {
    return {
      type: obj.objType.type,
      prop: obj.thisProp
    };
  } else {
    return {
      type: obj.objType.type,
      prop: obj.thatProp
    };
  }
}
如果
type
属性实际上嵌套在
objType
属性中,那么您会遇到问题字段,其中嵌套的属性在TypeScript中不受真正支持。你不能将一个受歧视的联盟作为另一个受歧视联盟的歧视者;判别式必须是诸如
“this”|“that”
之类的单例类型的并集


您不必等待microsoft/TypeScript#18758被寻址,您可以编写自己的代码,通过传递判别对象并使用来表示所需的缩小,其行为类似于嵌套的判别联合判别器。大概是这样的:

interface SomeObject {
    objType: ObjectType;
    thisProp: SomeObject['objType'] extends 'this' ? 'anything' : never;
    thatProp: SomeObject['objType'] extends 'that' ? 'something' : never;
}
type PickObject<T> = T extends 'this' ? ThisObject : ThatObject;

function getProp<T extends 'this' | 'that'>(obj: PickObject<T>) {
    switch (obj.objType.type) {
        case 'this':
            return {
                type: obj.objType.type,
                prop: obj.thisProp
            };
        case 'that':
            return {
                type: obj.objType.type,
                prop: obj.thatProp
            };
    }
}
interface ThisObject extends SomeObject { objType: { type: 'this' }; thisProp: 'anything' }
interface ThatObject extends SomeObject { objType: { type: 'that' }; thatProp: 'something' }
function nestedDiscrim<T extends object | PropertyKey, D extends object | PropertyKey>(
  val: T, discriminant: D): val is Extract<T, D>;
function nestedDiscrim(val: any, discriminant: any) {
  if ((typeof val === "object") && (typeof discriminant === "object")) {
    for (let k in discriminant) {
      if (!(k in val)) return false;
      if (!nestedDiscrim(val[k], discriminant[k])) return false;
    }
    return true;
  }
  if ((typeof val !== "object") && (typeof discriminant !== "object")) {
    return val === discriminant;
  }
  return false;
}
function getProp(obj: ThisObject | ThatObject) {
  if (nestedDiscrim(obj, { objType: { type: "this" } } as const)) {
    return {
      type: obj.objType.type,
      prop: obj.thisProp
    };
  } else {
    return {
      type: obj.objType.type,
      prop: obj.thatProp
    };
  }
}
您可以看到它是有效的:

console.log(getProp({ objType: { type: "this" }, thisProp: "anything" })); // {type: "this", prop: "anything"};
console.log(getProp({ objType: { type: "that" }, thatProp: "something" })); // {type: "that", prop: "something"};

其思想是,
nestedDiscrim(obj,{objType:{type:{type:{this“}}})
遍历
obj
,查看
obj.objType.type
,并将其与
“this”
进行比较。如果它们是相同的,那么我们将
obj
ThisObject | ThatObject
缩小为
ThisObject
。否则,我们将
obj
ThisObject | ThatObject
缩小为
ThatObject


好吧,希望这会有帮助;祝你好运


您能修复您的接口吗?大概您需要类似于
接口ThisObject扩展SomeObject{objType:{type:'this'};thisProp:'anythis'}
接口ThatObject扩展SomeObject{objType:{type:'that'};thatProp:'somethis'}
。不幸的是,这并不能神奇地发挥作用,但至少你的类型会与你实际做的相符。