microsoft / microsoft/TypeScript
Regression: Type T[K] as an array when sliced loses its type
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Go
- Sterne
- 111k
- Forks
- 14.4k
- Ø Merge
- 1 T. 19 Std.
- Gemergte PRs (30 T.)
- 117
Beschreibung
TypeScript Version: 3.4.5
Search Terms:
array property generics
Code
export function GetArrayProp<U, K extends string, T extends Record<K, U[]>>(
state: T,
prop: K,
) {
//good
let x1: T[K] = state[prop];
//good
let x2: U[] = state[prop];
//good
let x3: U[] = state[prop].slice(0);
//error
let x4: T[K] = state[prop].slice(0);
}
While you can argue that U[] isn't necessarily assignable to type T[K]. Look at the following code.
It's hard to see how TypeFromArray<T[K]>[]'s type should be any different than T[K]
export type TypeFromArray<T> = T extends (infer R)[] ? R : never;
export function GetArrayProp<K extends string, T extends Record<K, Array<TypeFromArray<T[K]>>>>(
obj: T,
prop: K,
) {
//good
let x1: T[K] = obj[prop];
//good
let x2 = obj[prop].slice(0);
//error Type 'TypeFromArray<T[K]>[]' is not assignable to type 'T[K]'.
let x3: T[K] = obj[prop].slice(0);
}
Expected behavior:
No errors.
T[K] and U[] should be assignable to each other.
state[prop].slice(0) should be of the same type as state[prop]
TypeFromArray<T[K]>[]'s type should be not be any different than T[K]
This code works in version 3.2.4 but stopped working in 3.3.1
Actual behavior:
Error Type 'U[]' is not assignable to type 'T[K]'.
Error Type 'TypeFromArray<T[K]>[]' is not assignable to type 'T[K]'
Playground Link:
My main goal is to be able to pluck array properties and modify the arrays without losing the type T[K]
The code above is simplified to show how TS is behaving.
See my use case below.
It's hard to see how TypeFromArray<T[K]>[]'s type should be any different than T[K]
The code below used to work when using 3.2.4
import { EntityState, EntityAdapter } from '@ngrx/entity';
import { Action } from '@ngrx/store';
export type TypeFromArray<T> = T extends (infer R)[] ? R : never;
type Selector<T> = (s: T) => boolean;
function ModifyEntityFromState<T>(entityId: number, state: EntityState<T>, callBack: (acnt: T) => void): T {
const t = state.entities[entityId];
const acnt = JSON.parse(JSON.stringify(t)) as T;
callBack(acnt);
return acnt;
}
export function ModifyPropertyFromState<T, K extends keyof T>(
entityId: number,
state: EntityState<T>,
prop: K,
callBack: (a: T[K]) => T[K],
): T {
return ModifyEntityFromState( entityId, state, (acnt) => {
acnt[prop] = callBack( acnt[prop] );
});
}
export function EditArrayFromState<
T extends Record<K, Array<TypeFromArray<T[K]>>>,
K extends keyof T,
U extends TypeFromArray<T[K]>
>(
entityId: number, state: EntityState<T>, prop: K,
selector: Selector<U>,
modified: U
): T {
return ModifyPropertyFromState( entityId, state, prop, (a) => {
//Argument of type '(a: T[K]) => TypeFromArray<T[K]>[]' is not assignable to parameter of type '(a: T[K]) => T[K]'.
// Type 'TypeFromArray<T[K]>[]' is not assignable to type 'T[K]'
const idx = a.findIndex(selector);
return [
...a.slice(0, idx),
...a.slice(idx + 1),
modified
];
});
}
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Reproduziere das Problem mit den bereitgestellten TypeScript-Snippets und dem Playground-Link und vergleiche dabei das Verhalten in 3.2.4, 3.3.1 und 3.4.5. Verfolge die Typprüfung für generische Indexed-Access- und Array-Slice-Typen, füge dann einen Regressionstest hinzu, der zeigt, dass der geslicte Wert weiterhin T[K] zuweisbar ist, und überprüfe die Testsuite.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- typescript
- Bereich
- compilers
- Issue-Typ
- Bug
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Aktiv
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 52/100