fix(common): let case conversion pipes accept type unions with `null` (#36259) (#37447)

The old implementation of case conversion types can handle several
values which are not strings, but the signature did not reflect this.

The new one reports errors when falsy non-string inputs are given to
the pipe (such as `false` or `0`) and has a new signature which
instead reflects the behaviour on `null` and `undefined`.

Fixes #36259

BREAKING CHANGE:
The case conversion pipes no longer let falsy values through. They now
map both `null` and `undefined` to `null` and raise an exception on
invalid input (`0`, `false`, `NaN`) just like most "common pipes". If
your code required falsy values to pass through, you need to handle them
explicitly.

PR Close #37447
This commit is contained in:
Andrea Canciani 2020-03-27 11:22:08 +01:00 committed by Alex Rickabaugh
parent 323be39297
commit c7d5555dfb
3 changed files with 54 additions and 9 deletions

View File

@ -194,6 +194,8 @@ export declare abstract class LocationStrategy {
export declare class LowerCasePipe implements PipeTransform { export declare class LowerCasePipe implements PipeTransform {
transform(value: string): string; transform(value: string): string;
transform(value: null | undefined): null;
transform(value: string | null | undefined): string | null;
} }
export declare class NgClass implements DoCheck { export declare class NgClass implements DoCheck {
@ -392,6 +394,8 @@ export declare type Time = {
export declare class TitleCasePipe implements PipeTransform { export declare class TitleCasePipe implements PipeTransform {
transform(value: string): string; transform(value: string): string;
transform(value: null | undefined): null;
transform(value: string | null | undefined): string | null;
} }
export declare enum TranslationWidth { export declare enum TranslationWidth {
@ -403,6 +407,8 @@ export declare enum TranslationWidth {
export declare class UpperCasePipe implements PipeTransform { export declare class UpperCasePipe implements PipeTransform {
transform(value: string): string; transform(value: string): string;
transform(value: null | undefined): null;
transform(value: string | null | undefined): string | null;
} }
export declare const VERSION: Version; export declare const VERSION: Version;

View File

@ -29,8 +29,11 @@ export class LowerCasePipe implements PipeTransform {
/** /**
* @param value The string to transform to lower case. * @param value The string to transform to lower case.
*/ */
transform(value: string): string { transform(value: string): string;
if (!value) return value; transform(value: null|undefined): null;
transform(value: string|null|undefined): string|null;
transform(value: string|null|undefined): string|null {
if (value == null) return null;
if (typeof value !== 'string') { if (typeof value !== 'string') {
throw invalidPipeArgumentError(LowerCasePipe, value); throw invalidPipeArgumentError(LowerCasePipe, value);
} }
@ -72,8 +75,11 @@ export class TitleCasePipe implements PipeTransform {
/** /**
* @param value The string to transform to title case. * @param value The string to transform to title case.
*/ */
transform(value: string): string { transform(value: string): string;
if (!value) return value; transform(value: null|undefined): null;
transform(value: string|null|undefined): string|null;
transform(value: string|null|undefined): string|null {
if (value == null) return null;
if (typeof value !== 'string') { if (typeof value !== 'string') {
throw invalidPipeArgumentError(TitleCasePipe, value); throw invalidPipeArgumentError(TitleCasePipe, value);
} }
@ -96,8 +102,11 @@ export class UpperCasePipe implements PipeTransform {
/** /**
* @param value The string to transform to upper case. * @param value The string to transform to upper case.
*/ */
transform(value: string): string { transform(value: string): string;
if (!value) return value; transform(value: null|undefined): null;
transform(value: string|null|undefined): string|null;
transform(value: string|null|undefined): string|null {
if (value == null) return null;
if (typeof value !== 'string') { if (typeof value !== 'string') {
throw invalidPipeArgumentError(UpperCasePipe, value); throw invalidPipeArgumentError(UpperCasePipe, value);
} }

View File

@ -25,8 +25,18 @@ import {LowerCasePipe, TitleCasePipe, UpperCasePipe} from '@angular/common';
expect(pipe.transform('BAr')).toEqual('bar'); expect(pipe.transform('BAr')).toEqual('bar');
}); });
it('should map null to null', () => {
expect(pipe.transform(null)).toEqual(null);
});
it('should map undefined to null', () => {
expect(pipe.transform(undefined)).toEqual(null);
});
it('should not support numbers', () => {
expect(() => pipe.transform(0 as any)).toThrowError();
});
it('should not support other objects', () => { it('should not support other objects', () => {
expect(() => pipe.transform(<any>{})).toThrowError(); expect(() => pipe.transform({} as any)).toThrowError();
}); });
}); });
@ -80,8 +90,18 @@ import {LowerCasePipe, TitleCasePipe, UpperCasePipe} from '@angular/common';
expect(pipe.transform('éric')).toEqual('Éric'); expect(pipe.transform('éric')).toEqual('Éric');
}); });
it('should map null to null', () => {
expect(pipe.transform(null)).toEqual(null);
});
it('should map undefined to null', () => {
expect(pipe.transform(undefined)).toEqual(null);
});
it('should not support numbers', () => {
expect(() => pipe.transform(0 as any)).toThrowError();
});
it('should not support other objects', () => { it('should not support other objects', () => {
expect(() => pipe.transform(<any>{})).toThrowError(); expect(() => pipe.transform({} as any)).toThrowError();
}); });
}); });
@ -101,8 +121,18 @@ import {LowerCasePipe, TitleCasePipe, UpperCasePipe} from '@angular/common';
expect(pipe.transform('bar')).toEqual('BAR'); expect(pipe.transform('bar')).toEqual('BAR');
}); });
it('should map null to null', () => {
expect(pipe.transform(null)).toEqual(null);
});
it('should map undefined to null', () => {
expect(pipe.transform(undefined)).toEqual(null);
});
it('should not support numbers', () => {
expect(() => pipe.transform(0 as any)).toThrowError();
});
it('should not support other objects', () => { it('should not support other objects', () => {
expect(() => pipe.transform(<any>{})).toThrowError(); expect(() => pipe.transform({} as any)).toThrowError();
}); });
}); });
} }