好吧,我一直在切换到使用Typescript。一定要说,我喜欢它发现不到明显错误的方式。但是有时候……有时候我只是left着脑子想知道“这是什么鬼话?”
例如:
/*-!!! Type declarations at the bottom. !!!-*/
/**
* Array literal constructor with '' as first element assigned to absPath.
*/
const bobHome: absPathBob = ['', 'home', 'bob']; //works
const timHome: absPathTim = ['', 'home', 'tim']; //works
/**
* `absPathBob` (type alias) and `absPathTime` (interface) are not quite the
* assignable to each other, though this isn't particularly unexpected.
*/
const bobNeighbor1: absPathBob = timHome; //Type 'absPathTim' is not assignable to type '["", ...string[]]'.ts(2322)
const timNeighbor1: absPathTim = bobHome; //works
/**
* absPath->array typecasting via spread operators should be equivalent to the
* original array literal constructor... but isn't
*/
const bobHome2: absPathBob = [...bobHome]; //Property '0' is missing in type 'string[]' but required in type '["", ...string[]]'.ts(2741)
const timHome2: absPathTim = [...timHome]; //Property '0' is missing in type 'string[]' but required in type 'absPathTim'.ts(2741)
/**
* absPath->array typecasting via concatenation should also be equivalent to the
* original array literal constructor... but also isn't
*/
const bobHome3: absPathBob = [].concat(bobHome); //Property '0' is missing in type 'any[]' but required in type '["", ...string[]]'.ts(2741)
const timHome3: absPathTim = [].concat(timHome); //Property '0' is missing in type 'any[]' but required in type 'absPathTim'.ts(2741)
/**
* Relative path for concatenating onto the end of home paths.
*/
const userMusic: relPathBob = ['Multimedia', 'Music']; //works
const userVideo: relPathTim = ['Multimedia', 'Video']; //works
/**
* Using spread for concatenation of absPaths with relPaths fails.
*/
const bobMusic: absPathBob = [...bobHome, ...userMusic]; //Type 'string[]' is not assignable to type '["", ...string[]]'.ts(2322)
const timVideo: absPathTim = [...timHome, ...userVideo]; //Type 'string[]' is not assignable to type 'absPathTim'.ts(2322)
/**
* Using Array.prototype.concat() for concatenation of absPaths with relPaths
* also fails.
*/
const bobMusic2: absPathBob = bobHome.concat(userMusic); //Type 'string[]' is not assignable to type '["", ...string[]]'.ts(2322)
const timVideo2: absPathTim = timHome.concat(userVideo); //Type 'string[]' is not assignable to type 'absPathTim'.ts(2322)
/**
* Appending string via spread->array fails.
*/
const bobConfig: absPathBob = [...bobHome, '.config']; //Type 'string[]' is not assignable to type '["", ...string[]]'.ts(2322)
const timSSH : absPathTim = [...timHome, '.ssh' ]; //Type 'string[]' is not assignable to type 'absPathTim'.ts(2322)
/**
* Appending string via spread->array fails.
*/
const bobConfig: absPathBob = [...bobHome, '.config']; //Type 'string[]' is not assignable to type '["", ...string[]]'.ts(2322)
const timSSH : absPathTim = [...timHome, '.ssh' ]; //Type 'string[]' is not assignable to type 'absPathTim'.ts(2322)
/**
* A dirty hack to trick typescript works with spread operator.
*/
const bobHax1: absPathBob = ['', ...bobHome.slice(1)]; //works
const timHax1: absPathTim = ['', ...bobHome.slice(1)]; //works
/**
* Similar dirty hack fails with Array.prototype.concat()
*/
const bobHax12: absPathBob = [''].concat(bobHome.slice(1)); //Type 'string[]' is not assignable to type '["", ...string[]]'.ts(2322)
const timHax12: absPathTim = [''].concat(bobHome.slice(1)); //Type 'string[]' is not assignable to type 'absPathTim'.ts(2322)
/**
* WTF? What sorcery is this?
*/
const bobHax2: absPathBob = ['', ...bobHome.slice(1), 'hax']; //Type 'string[]' is not assignable to type '["", ...string[]]'.ts(2322)
const timHax2: absPathTim = ['', ...bobHome.slice(1), 'hax']; //Type 'string[]' is not assignable to type 'absPathTim'.ts(2322)
/**
* WTF? What sorcery is this?
*/
const bobHax22: absPathBob = ['', ...bobHome.slice(1), 'hax']; //Type 'string[]' is not assignable to type '["", ...string[]]'.ts(2322)
const timHax22: absPathTim = ['', ...bobHome.slice(1), 'hax']; //Type 'string[]' is not assignable to type 'absPathTim'.ts(2322)
/**
* Array.prototype.shift() (as well as unshift, push, and pop) works fine...
* but requires copying the absPath to a new absPath so as not to change the
* original.
*/
const bobHax3: absPathBob = bobHome; //works
const timHax3: absPathTim = timHome; //works
bobHax3.shift();
timHax3.shift();
/**
* Using an accumulator/for-loop pattern works.
*/
const bobLoop1: absPathBob = (() => { //works
const accumulator = bobHome;
for (let i = 0; i < userMusic.length; i++) accumulator.push(userMusic[i]);
return accumulator;
})();
const timLoop1: absPathTim = (() => { //works
const accumulator = timHome;
for (let i = 0; i < userVideo.length; i++) accumulator.push(userVideo[i]);
return accumulator;
})();
/**
* But only if the accumulator starts out as an absPath
*/
const bobLoop2: absPathBob = (() => { //Type 'string[]' is not assignable to type '["", ...string[]]'.ts(2322)
const accumulator: string[] = []
for (let i = 0; i < bobHome.length; i++) accumulator.push(bobHome[i]);
for (let i = 0; i < userMusic.length; i++) accumulator.push(userMusic[i]);
return accumulator;
})();
const timLoop2: absPathTim = (() => { //Type 'string[]' is not assignable to type 'absPathTim'.ts(2322)
const accumulator: string[] = []
for (let i = 0; i < bobHome.length; i++) accumulator.push(bobHome[i]);
for (let i = 0; i < userVideo.length; i++) accumulator.push(userVideo[i]);
return accumulator;
})();
const bobLoop3: absPathBob = (() => { //works
const accumulator: absPathBob = ['']
for (let i = 1; i < bobHome.length; i++) accumulator.push(bobHome[i]);
for (let i = 0; i < userMusic.length; i++) accumulator.push(userMusic[i]);
return accumulator;
})();
const timLoop3: absPathTim = (() => { //works
const accumulator: absPathTim = ['']
for (let i = 1; i < bobHome.length; i++) accumulator.push(bobHome[i]);
for (let i = 0; i < userVideo.length; i++) accumulator.push(userVideo[i]);
return accumulator;
})();
const bobLoop4: absPathBob = (() => { //Type 'string[]' is not assignable to type '["", ...string[]]'.ts(2322)
const accumulator: string[] = ['']
for (let i = 1; i < bobHome.length; i++) accumulator.push(bobHome[i]);
for (let i = 0; i < userMusic.length; i++) accumulator.push(userMusic[i]);
return accumulator;
})();
const timLoop4: absPathTim = (() => { //Type 'string[]' is not assignable to type 'absPathTim'.ts(2322)
const accumulator: string[] = ['']
for (let i = 1; i < bobHome.length; i++) accumulator.push(bobHome[i]);
for (let i = 0; i < userVideo.length; i++) accumulator.push(userVideo[i]);
return accumulator;
})();
type relPathBob = [...string[]];
type absPathBob = ['', ...string[]];
interface relPathTim extends Array<string> {
[n: number]: string;
}
interface absPathTim extends relPathTim {
0: '';
}
基本思想应该很简单。字符串数组是路径。以''
开头的字符串数组是绝对路径。这不是一个新主意。给定分层数据结构(如硬盘驱动器上的文件系统...或DOM),每个节点都具有标识它的特定路径。通过从数组中添加和删除元素,您可以“导航”文件树/ DOM以查找相对于当前节点的其他节点。
实际上,我一直在JavaScript中使用此代码来实现这样的分层数据结构,这是较大项目的一部分。一直很好。我想:“呵呵……让Typescript在编译时检查我的工作肯定是一件好事,并确保当我需要绝对路径时,我永远不会偶然尝试使用相对路径。您知道...而不是乱扔垃圾具有运行时类型的代码将全面保护。”
好吧..显然Typescript认为这是一个糟糕的主意。但是为什么呢?
看着它,似乎与使用散布运算符有关。我知道为什么不想要在rest运算符之后的元素...但是对于分散运算符,这对我来说没有意义。我还了解到,在这种情况下,散布运算符正在使用内置数组的可迭代协议...这可能是问题的根源,因为我能够使用累加器/ for循环模式使其工作。因此,当涉及到可迭代的协议时,也许只是打字稿无法跟踪“ Home”数组的['',...]-性...除了Hax2示例使这一想法火上浇油。
我离开时想这是:
有人能帮我了解上面示例中的情况吗?
地狱,当我在这里时...有一种更聪明的方式来从事这条道路吗?
编辑:这似乎也影响Array.prototype.concat()。但并非始终如一。它也不会持续影响散布操作员。