Typescript 这是打字脚本错误吗?“错误”;不可分配给“类型”;向对象添加额外属性时

Typescript 这是打字脚本错误吗?“错误”;不可分配给“类型”;向对象添加额外属性时,typescript,typescript-typings,Typescript,Typescript Typings,我正在使用两个API,它们对经度坐标使用不同的属性名称:lon和lng。我正在编写一个转换器函数,它添加了可选的属性名,以便两个API中的位置可以互换使用 这个函数给出了一个错误,在我看来确实是一个bug。我知道很多解决方法,但我有兴趣了解发生此错误的原因。这是一只虫子,还是我在这里遗漏了什么 const fillLonLng1 = <T extends LatLng | LatLon>(loc: T): T & LatLon & LatLng => {

我正在使用两个API,它们对经度坐标使用不同的属性名称:
lon
lng
。我正在编写一个转换器函数,它添加了可选的属性名,以便两个API中的位置可以互换使用

这个函数给出了一个错误,在我看来确实是一个bug。我知道很多解决方法,但我有兴趣了解发生此错误的原因。这是一只虫子,还是我在这里遗漏了什么

const fillLonLng1 = <T extends LatLng | LatLon>(loc: T): T & LatLon & LatLng => {
    if ( isLatLon(loc) ) {
        return {...loc, lng: loc.lon};
    } else {
        return {...loc, lon: loc.lng};
    }
}
Typescript正确理解返回的值包含
lat
lon
,这两个值都是
number
。我不明白这怎么可能不分配给
LatLon
,定义如下:

interface LatLon {
    lat: number;
    lon: number;
}
const isLatLon=(loc:T):loc是T&LatLon=>{
返回loc.lat!==未定义和&loc.lon!==未定义;
}

。我发现了两种不同的方法,它们不会产生任何错误(也不依赖于
as
)。一个是我把它分成两个独立的函数,另一个是愚蠢的复杂类型。

,这可能是在中提到的编译器错误

通过将
LatLon&LatLng
重构为编译器认为与
{lng:number;lat:number;lon:number;}
相同的类型,可以说服编译器接受它:

interface LatLonLng extends LatLon, LatLng { }
const fillLonLng1 = <T extends LatLng | LatLon>(loc: T): T & LatLonLng => {
    if (isLatLon(loc)) {
        return { ...loc, lng: loc.lon };
    } else if (isLatLng(loc)) {
        return { ...loc, lon: (loc as LatLng).lng };
    } else throw new Error();
}
接口LatLonLng扩展LatLon,LatLng{}
常数fillLonLng1=(位置:T):T&LatLonLng=>{
国际单项体育联合会(伊斯拉特隆(loc)){
返回{…loc,lng:loc.lon};
}否则,如果(isLatLng(loc)){
返回{…loc,lon:(loc为LatLng).lng};
}否则抛出新错误();
}
下面的警告仍然有效(即使它们不像我最初认为的那样直接适用这应该是:

interface LatLon {
  lat: number;
  lon: number;
}
namespace LatLon {
  export function is(loc: object): loc is LatLon {
    return ['lat', 'lon'].every(key => key in loc && loc[key] !== undefined);
  }
}

type LatLng = { lat: number; lng: number; };

export function fillLonLng(loc: LatLng | LatLon): LatLon & LatLng {
  return LatLon.is(loc) ? { ...loc, lng: loc.lon } : { ...loc, lon: loc.lng };
}

“isLatLon”的类型是什么?它是一个类型保护函数
const isLatLon=(loc:T):loc是T&LatLon
。我将把它编辑成这个问题。感谢分享您的知识:)我考虑了数字文字的可能性,这就是为什么我提出了
省略
版本。但如果这就是问题所在,那么错误信息是错误的,对吗?应该是返回的类型不可分配给
T
,而是说它不可分配给
LatLon
,它总是这样。嗯,不确定。当我再次接触到一台真正的电脑时,我会看看;它可能更像是验证未指定泛型类型的可分配性的一般限制;编译器不太努力,因为它通常不能正确地完成它,而且这样做通常是一个(有时是微妙的)错误。是的,看看它,我同意你的看法:编译器并没有真正费心在这里验证可分配性。我看你是否能像编译器一样进行重构(
LatLonLng
相当于
LatLon&LatLng
,但是当与
T
相交时,它们的处理方式不同)。我认为这仍然是一个潜在的问题,但我不知道他们是否会考虑这个特定的问题。可能很有趣!我不知道
LatLonLng
会受到与工会不同的待遇。
interface LatLonLng extends LatLon, LatLng { }
const fillLonLng1 = <T extends LatLng | LatLon>(loc: T): T & LatLonLng => {
    if (isLatLon(loc)) {
        return { ...loc, lng: loc.lon };
    } else if (isLatLng(loc)) {
        return { ...loc, lon: (loc as LatLng).lng };
    } else throw new Error();
}
interface LatLon {
  lat: number;
  lon: number;
}
namespace LatLon {
  export function is(loc: object): loc is LatLon {
    return ['lat', 'lon'].every(key => key in loc && loc[key] !== undefined);
  }
}

type LatLng = { lat: number; lng: number; };

export function fillLonLng(loc: LatLng | LatLon): LatLon & LatLng {
  return LatLon.is(loc) ? { ...loc, lng: loc.lon } : { ...loc, lon: loc.lng };
}