javascript - TypeError: Kan inte läsa egenskapen 'toArray' av null i Context. i Typescript
När jag försöker använda toArray-funktionen på en nyss skapad lista får jag hela tiden detta felmeddelande "TypeError: Cannot read property 'toArray' of null at Context".
Jag försöker skapa en implementation av en länkad lista. Funktionen toArray får inte ändras men jag är ganska säker på att problemet måste ligga i reduce-funktionen, om inte där så kanske i fromArray-funktionen
type Selector<T> = (head:T, rest?:Cons<T>)=> T|Cons<T>;
type Cons<T> = (selector: Selector<T>) => T|Cons<T>;
function cons<T>(head:T, rest?: Cons<T>): Cons<T> {
return (selector: Selector<T>) => selector(head, rest);
}
function head<T>(list:Cons<T>):T {
return <T>list((head, rest?) => head);
}
function rest<T>(list:Cons<T>):Cons<T> {
return <Cons<T>>list((head, rest?) => rest);
}
function fromArray<T>(arr:T[]):Cons<T>{
function aux(array:T[], i:number):Cons<T>{
if(i<array.length){
return cons(array[i], aux(array.slice(i+1), i))
}
else{
return null
}
}
return aux(arr, 0);
}
function reduce<T>(f:(x:T, y:T)=>T, initial:T, list:any):T {
if(list){
return reduce(f, f(initial, head(list)), rest(list));
}
else{
return initial;
}
}
class List<T> {
private head: Cons<T>;
constructor(list: T[] | Cons<T>) {
if (list instanceof Array) {
this.head = fromArray(list);
} else {
this.head = list;
}
}
toArray(): T[] {
return reduce((a,t)=>(a.push(t), a), [], this.head).reverse();
}
Svar #1
Du bör slå på strictNullChecks-kompilatoralternativet, eftersom det finns mycket undefined och null som cirkulerar i din kod utan att flagga några fel. Huvudproblemet här är att i din implementation är den tomma listan helt enkelt undefined (eller kanske null), och du kontrollerar inte för den på tillräckligt många ställen. Följande är vad jag debugade till att vara; jag vet inte om alla buggar är borta, men toArray() verkar fungera nu. Jag lade till några kommentarer där jag ändrade saker:
type Selector<T> = (head: T, rest?: Cons<T>) => T | Cons<T>;
// a list can be undefined, so I added it:
type Cons<T> = undefined | ((selector: Selector<T>) => T | Cons<T>);
function cons<T>(head: T, rest?: Cons<T>): Cons<T> {
return (selector: Selector<T>) => selector(head, rest);
}
// the head function is guaranteed to return a T only on a non-empty list,
// so I overloaded it:
function head(list: undefined): undefined;
function head<T>(list: Cons<T>): T;
function head<T>(list: Cons<T>): T | undefined {
if (!list) return; // watch out for empty list
return <T>list((head, rest?) => head);
}
function rest<T>(list: Cons<T>): Cons<T> {
if (!list) return; // watch out for empty list
return <Cons<T>>list((head, rest?) => rest);
}
function fromArray<T>(arr: T[]): Cons<T> {
function aux(array: T[], i: number): Cons<T> {
if (i < array.length) {
return cons(array[i], aux(array.slice(i + 1), i))
}
else {
return; // use undefined instead of null, easier this way
}
}
return aux(arr, 0);
}
// note that you want reduce to return a T[] instead of a T in toArray()
// that means your f cannot be (x:T, y:T) => T. Add a U parameter for the
// type of initial, return value, and the return type of f
function reduce<T, U>(f: (x: U, y: T) => U, initial: U, list: Cons<T>): U {
if (list) {
return reduce(f, f(initial, head(list)), rest(list));
}
else {
return initial;
}
}
class List<T> {
private head: Cons<T>;
constructor(list: T[] | Cons<T>) {
if (list instanceof Array) {
this.head = fromArray(list);
} else {
this.head = list;
}
}
toArray(): T[] {
// push puts things at the end; you're trying to cons, right?
// that's unshift
return reduce<T, T[]>((a, t) => (a.unshift(t), a), [], this.head).reverse();
}
}
Hoppas det hjälper; lycka till!
