Skip to content

Commit 70338af

Browse files
committed
feat(locale): 🎸 improve strict mode types for pipes
Keep null and undefined intact and provide overloads with null and undefined values for all pipes. BREAKING CHANGE: 🧨 Pipes return null or undefined instead of an empty string if the input is null or undefined ✅ Closes: #755
1 parent 09df44c commit 70338af

8 files changed

+178
-34
lines changed

libs/transloco-locale/src/lib/pipes/transloco-currency.pipe.ts

+28-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212

1313
import { BaseLocalePipe } from './base-locale.pipe';
1414

15+
type CurrencyDisplayType = 'code' | 'symbol' | 'narrowSymbol' | 'name';
16+
1517
@Pipe({
1618
name: 'translocoCurrency',
1719
pure: false,
@@ -35,14 +37,37 @@ export class TranslocoCurrencyPipe
3537
* 1000000 | translocoCurrency: 'narrowSymbol' : {minimumFractionDigits: 0 } : CAD // $1,000,000
3638
*
3739
*/
40+
// overloads for strict mode
3841
transform(
3942
value: number | string,
40-
display: 'code' | 'symbol' | 'narrowSymbol' | 'name' = 'symbol',
43+
display?: CurrencyDisplayType,
44+
numberFormatOptions?: NumberFormatOptions,
45+
currencyCode?: Currency,
46+
locale?: Locale
47+
): string;
48+
transform<T extends null | undefined>(
49+
value: T,
50+
display?: CurrencyDisplayType,
51+
numberFormatOptions?: NumberFormatOptions,
52+
currencyCode?: Currency,
53+
locale?: Locale
54+
): T;
55+
transform<T extends null | undefined>(
56+
value: number | string | T,
57+
display?: CurrencyDisplayType,
58+
numberFormatOptions?: NumberFormatOptions,
59+
currencyCode?: Currency,
60+
locale?: Locale
61+
): string | T;
62+
63+
transform(
64+
value?: number | string | null,
65+
display: CurrencyDisplayType = 'symbol',
4166
numberFormatOptions: NumberFormatOptions = {},
4267
currencyCode?: Currency,
4368
locale?: Locale
44-
): string {
45-
if (isNil(value)) return '';
69+
): string | null | undefined {
70+
if (isNil(value)) return value;
4671
locale = this.getLocale(locale);
4772

4873
const options = {

libs/transloco-locale/src/lib/pipes/transloco-date.pipe.ts

+23-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,29 @@ export class TranslocoDatePipe extends BaseLocalePipe implements PipeTransform {
3434
* 1 | translocoDate: { dateStyle: 'medium' } // Jan 1, 1970
3535
* '2019-02-08' | translocoDate: { dateStyle: 'medium' } // Feb 8, 2019
3636
*/
37-
transform(date: ValidDate, options: DateFormatOptions = {}, locale?: Locale) {
38-
if (isNil(date)) return '';
37+
// overloads for strict mode
38+
transform(
39+
date: ValidDate,
40+
options?: DateFormatOptions,
41+
locale?: Locale
42+
): string;
43+
transform<T extends null | undefined>(
44+
date: T,
45+
options?: DateFormatOptions,
46+
locale?: Locale
47+
): T;
48+
transform<T extends null | undefined>(
49+
date: ValidDate | T,
50+
options?: DateFormatOptions,
51+
locale?: Locale
52+
): string | T;
53+
54+
transform(
55+
date: ValidDate | null | undefined,
56+
options: DateFormatOptions = {},
57+
locale?: Locale
58+
): string | null | undefined {
59+
if (isNil(date)) return date;
3960
locale = this.getLocale(locale);
4061

4162
return this.localeService.localizeDate(date, locale, {

libs/transloco-locale/src/lib/pipes/transloco-decimal.pipe.ts

+20-3
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,29 @@ export class TranslocoDecimalPipe
3131
* 1234567890 | translocoDecimal: {useGrouping: false}: en-US // 1234567890
3232
*
3333
*/
34+
// overloads for strict mode
3435
transform(
35-
value: string | number,
36+
value: number | string,
37+
numberFormatOptions?: NumberFormatOptions,
38+
locale?: Locale
39+
): string;
40+
transform<T extends null | undefined>(
41+
value: T,
42+
numberFormatOptions?: NumberFormatOptions,
43+
locale?: Locale
44+
): T;
45+
transform<T extends null | undefined>(
46+
value: number | string | T,
47+
numberFormatOptions?: NumberFormatOptions,
48+
locale?: Locale
49+
): string | T;
50+
51+
transform(
52+
value?: string | number | null,
3653
numberFormatOptions: NumberFormatOptions = {},
3754
locale?: Locale
38-
): string {
39-
if (isNil(value)) return '';
55+
): string | null | undefined {
56+
if (isNil(value)) return value;
4057
locale = this.getLocale(locale);
4158

4259
const options = {

libs/transloco-locale/src/lib/pipes/transloco-percent.pipe.ts

+19-2
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,29 @@ export class TranslocoPercentPipe
3131
* "1" | translocoPercent : {} : en-US // 100%
3232
*
3333
*/
34+
// overloads for strict mode
3435
transform(
3536
value: number | string,
37+
numberFormatOptions?: NumberFormatOptions,
38+
locale?: Locale
39+
): string;
40+
transform<T extends null | undefined>(
41+
value: T,
42+
numberFormatOptions?: NumberFormatOptions,
43+
locale?: Locale
44+
): T;
45+
transform<T extends null | undefined>(
46+
value: number | string | T,
47+
numberFormatOptions?: NumberFormatOptions,
48+
locale?: Locale
49+
): string | T;
50+
51+
transform(
52+
value?: number | string | null,
3653
numberFormatOptions: NumberFormatOptions = {},
3754
locale?: Locale
38-
): string {
39-
if (isNil(value)) return '';
55+
): string | null | undefined {
56+
if (isNil(value)) return value;
4057
locale = this.getLocale(locale);
4158

4259
const options = {

libs/transloco-locale/src/lib/tests/pipes/transloco-currency.pipe.spec.ts

+22-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { SpectatorPipe } from '@ngneat/spectator';
2+
import { ChangeDetectorRef } from '@angular/core';
3+
import { TestBed } from '@angular/core/testing';
4+
import { Mock } from 'ts-mocks';
25

36
import { TranslocoCurrencyPipe } from '../../pipes/transloco-currency.pipe';
47
import { LOCALE_CONFIG_MOCK, provideTranslocoServiceMock } from '../mocks';
@@ -60,17 +63,30 @@ describe('TranslocoCurrencyPipe', () => {
6063
});
6164

6265
describe('None transformable values', () => {
66+
let pipe: TranslocoCurrencyPipe;
67+
let cdrMock: ChangeDetectorRef;
68+
69+
beforeEach(() => {
70+
cdrMock = new Mock<ChangeDetectorRef>({
71+
markForCheck: () => {},
72+
}).Object;
73+
74+
TestBed.configureTestingModule({
75+
providers: [{ provide: ChangeDetectorRef, useValue: cdrMock }],
76+
});
77+
pipe = TestBed.runInInjectionContext(() => new TranslocoCurrencyPipe());
78+
});
6379
it('should handle null', () => {
64-
spectator = pipeFactory(`{{ null | translocoCurrency }}`);
65-
expect(spectator.element).toHaveText('');
80+
expect(pipe.transform(null)).toBeNull();
81+
});
82+
it('should handle undefined', () => {
83+
expect(pipe.transform(undefined)).toBeUndefined();
6684
});
6785
it('should handle {}', () => {
68-
spectator = pipeFactory(`{{ {} | translocoCurrency }}`);
69-
expect(spectator.element).toHaveText('');
86+
expect(pipe.transform({} as any)).toBe('');
7087
});
7188
it('should handle none number string', () => {
72-
spectator = pipeFactory(`{{ 'none number string' | translocoCurrency }}`);
73-
expect(spectator.element).toHaveText('');
89+
expect(pipe.transform('none number string')).toBe('');
7490
});
7591
});
7692

libs/transloco-locale/src/lib/tests/pipes/transloco-date.pipe.spec.ts

+22-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { SpectatorPipe } from '@ngneat/spectator';
2+
import { ChangeDetectorRef } from '@angular/core';
3+
import { TestBed } from '@angular/core/testing';
4+
import { Mock } from 'ts-mocks';
25

36
import { TranslocoDatePipe } from '../../pipes';
47
import {
@@ -88,17 +91,30 @@ describe('TranslocoDatePipe', () => {
8891
});
8992

9093
describe('None date values', () => {
94+
let pipe: TranslocoDatePipe;
95+
let cdrMock: ChangeDetectorRef;
96+
97+
beforeEach(() => {
98+
cdrMock = new Mock<ChangeDetectorRef>({
99+
markForCheck: () => {},
100+
}).Object;
101+
102+
TestBed.configureTestingModule({
103+
providers: [{ provide: ChangeDetectorRef, useValue: cdrMock }],
104+
});
105+
pipe = TestBed.runInInjectionContext(() => new TranslocoDatePipe());
106+
});
91107
it('should handle null', () => {
92-
spectator = pipeFactory(`{{ null | translocoDate }}`);
93-
expect(spectator.element).toHaveText('');
108+
expect(pipe.transform(null)).toBeNull();
109+
});
110+
it('should handle undefined', () => {
111+
expect(pipe.transform(undefined)).toBeUndefined();
94112
});
95113
it('should handle {}', () => {
96-
spectator = pipeFactory(`{{ {} | translocoDate }}`);
97-
expect(spectator.element).toHaveText('');
114+
expect(pipe.transform({} as any)).toBe('');
98115
});
99116
it('should handle none number string', () => {
100-
spectator = pipeFactory(`{{ 'none number string' | translocoDate }}`);
101-
expect(spectator.element).toHaveText('');
117+
expect(pipe.transform('none number string')).toBe('');
102118
});
103119
});
104120

libs/transloco-locale/src/lib/tests/pipes/transloco-decimal.pipe.spec.ts

+22-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { SpectatorPipe } from '@ngneat/spectator';
2+
import { ChangeDetectorRef } from '@angular/core';
3+
import { TestBed } from '@angular/core/testing';
4+
import { Mock } from 'ts-mocks';
25

36
import { TranslocoDecimalPipe } from '../../pipes';
47
import {
@@ -66,17 +69,30 @@ describe('TranslocoDecimalPipe', () => {
6669
});
6770

6871
describe('None transformable values', () => {
72+
let pipe: TranslocoDecimalPipe;
73+
let cdrMock: ChangeDetectorRef;
74+
75+
beforeEach(() => {
76+
cdrMock = new Mock<ChangeDetectorRef>({
77+
markForCheck: () => {},
78+
}).Object;
79+
80+
TestBed.configureTestingModule({
81+
providers: [{ provide: ChangeDetectorRef, useValue: cdrMock }],
82+
});
83+
pipe = TestBed.runInInjectionContext(() => new TranslocoDecimalPipe());
84+
});
6985
it('should handle null', () => {
70-
spectator = pipeFactory(`{{ null | translocoDecimal }}`);
71-
expect(spectator.element).toHaveText('');
86+
expect(pipe.transform(null)).toBeNull();
87+
});
88+
it('should handle undefined', () => {
89+
expect(pipe.transform(undefined)).toBeUndefined();
7290
});
7391
it('should handle {}', () => {
74-
spectator = pipeFactory(`{{ {} | translocoDecimal }}`);
75-
expect(spectator.element).toHaveText('');
92+
expect(pipe.transform({} as any)).toBe('');
7693
});
7794
it('should handle none number string', () => {
78-
spectator = pipeFactory(`{{ 'none number string' | translocoDecimal }}`);
79-
expect(spectator.element).toHaveText('');
95+
expect(pipe.transform('none number string')).toBe('');
8096
});
8197
});
8298
});

libs/transloco-locale/src/lib/tests/pipes/transloco-percent.pipe.spec.ts

+22-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { SpectatorPipe } from '@ngneat/spectator';
2+
import { ChangeDetectorRef } from '@angular/core';
3+
import { TestBed } from '@angular/core/testing';
4+
import { Mock } from 'ts-mocks';
25

36
import { TranslocoPercentPipe } from '../../pipes';
47
import { LOCALE_CONFIG_MOCK, provideTranslocoLocaleConfigMock } from '../mocks';
@@ -31,17 +34,30 @@ describe('TranslocoPercentPipe', () => {
3134
});
3235

3336
describe('None transformable values', () => {
37+
let pipe: TranslocoPercentPipe;
38+
let cdrMock: ChangeDetectorRef;
39+
40+
beforeEach(() => {
41+
cdrMock = new Mock<ChangeDetectorRef>({
42+
markForCheck: () => {},
43+
}).Object;
44+
45+
TestBed.configureTestingModule({
46+
providers: [{ provide: ChangeDetectorRef, useValue: cdrMock }],
47+
});
48+
pipe = TestBed.runInInjectionContext(() => new TranslocoPercentPipe());
49+
});
3450
it('should handle null', () => {
35-
spectator = pipeFactory(getPipeTpl(null));
36-
expect(spectator.element).toHaveText('');
51+
expect(pipe.transform(null)).toBeNull();
52+
});
53+
it('should handle undefined', () => {
54+
expect(pipe.transform(undefined)).toBeUndefined();
3755
});
3856
it('should handle {}', () => {
39-
spectator = pipeFactory(getPipeTpl({}));
40-
expect(spectator.element).toHaveText('');
57+
expect(pipe.transform({} as any)).toBe('');
4158
});
4259
it('should handle none number string', () => {
43-
spectator = pipeFactory(getPipeTpl('none number string'));
44-
expect(spectator.element).toHaveText('');
60+
expect(pipe.transform('none number string')).toBe('');
4561
});
4662
});
4763

0 commit comments

Comments
 (0)