feat(common): stricter types for SlicePipe (#30156)

Adds overloads to the `transform` methods of `SlicePipe`,
to have better types than `any` for `value` and `any` as a return.
With this commit, using `slice` in an `ngFor` still allow to type-check the content of the `ngFor`
with `fullTemplateTypeCheck` enabled in Ivy:

    <div *ngFor="let user of users | slice:0:2">{{ user.typo }}</div>
                                                        |
                                                        `typo` does not exist on type `UserModel`

whereas it is currently not catched (as the return of `slice` is `any`) neither in VE nor in Ivy.

BREAKING CHANGE
`SlicePipe` now only accepts an array of values, a string, null or undefined.
This was already the case in practice, and it still throws at runtime if another type is given.
But it is now a compilation error to try to call it with an unsupported type.

PR Close #30156
This commit is contained in:
cexbrayat 2019-04-26 11:37:53 +02:00 committed by Jason Aden
parent 661a57d9e2
commit 95830ee584
3 changed files with 16 additions and 2 deletions

View File

@ -62,6 +62,10 @@ export class SlicePipe implements PipeTransform {
* - **if positive**: return all items before `end` index of the list or string.
* - **if negative**: return all items before `end` index from the end of the list or string.
*/
transform<T>(value: ReadonlyArray<T>, start: number, end?: number): Array<T>;
transform(value: string, start: number, end?: number): string;
transform(value: null, start: number, end?: number): null;
transform(value: undefined, start: number, end?: number): undefined;
transform(value: any, start: number, end?: number): any {
if (value == null) return value;

View File

@ -26,9 +26,13 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
describe('supports', () => {
it('should support strings', () => { expect(() => pipe.transform(str, 0)).not.toThrow(); });
it('should support lists', () => { expect(() => pipe.transform(list, 0)).not.toThrow(); });
it('should support readonly lists',
() => { expect(() => pipe.transform(list as ReadonlyArray<number>, 0)).not.toThrow(); });
it('should not support other objects',
() => { expect(() => pipe.transform({}, 0)).toThrow(); });
// this would not compile
// so we cast as `any` to check that it throws for unsupported objects
() => { expect(() => pipe.transform({} as any, 0)).toThrow(); });
});
describe('transform', () => {
@ -36,6 +40,9 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
it('should return null if the value is null',
() => { expect(pipe.transform(null, 1)).toBe(null); });
it('should return undefined if the value is undefined',
() => { expect(pipe.transform(undefined, 1)).toBe(undefined); });
it('should return all items after START index when START is positive and END is omitted',
() => {
expect(pipe.transform(list, 3)).toEqual([4, 5]);

View File

@ -410,7 +410,10 @@ export interface PopStateEvent {
export declare function registerLocaleData(data: any, localeId?: string | any, extraData?: any): void;
export declare class SlicePipe implements PipeTransform {
transform(value: any, start: number, end?: number): any;
transform<T>(value: ReadonlyArray<T>, start: number, end?: number): Array<T>;
transform(value: string, start: number, end?: number): string;
transform(value: null, start: number, end?: number): null;
transform(value: undefined, start: number, end?: number): undefined;
}
export declare type Time = {