Skip to content

Commit 7739788

Browse files
authored
types(TFunction): make return not inferrable and use defaultValue as return when provided (#2234)
1 parent e5170ad commit 7739788

File tree

9 files changed

+40
-27
lines changed

9 files changed

+40
-27
lines changed

test/typescript/custom-types-default-ns-as-array/i18nextT.test.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ describe('i18next.t', () => {
7070
});
7171

7272
it('should accept any key if default value is provided', () => {
73-
const str: string = i18next.t('unknown-ns:unknown-key', 'default value');
74-
assertType<string>(str);
73+
assertType<'default value'>(i18next.t('unknown-ns:unknown-key', 'default value'));
7574
});
7675

7776
it('should work with plurals', () => {

test/typescript/custom-types-default-ns-as-array/t.test.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,12 @@ describe('t', () => {
9393
assertType<string[]>(result);
9494
});
9595

96-
it('should not throw an error when `defaultValue` is provided', () => {
96+
it('should not throw an error when `defaultValue` is provided and value should be equal to DefaultValue', () => {
9797
expectTypeOf(
9898
t('foobar.barfoo', { defaultValue: 'some default value' }),
99-
).toMatchTypeOf<unknown>();
100-
expectTypeOf(t('new.key', { defaultValue: 'some default value' })).toEqualTypeOf<unknown>();
101-
expectTypeOf(t('new.key', 'some default value')).toEqualTypeOf<unknown>();
99+
).toMatchTypeOf<string>();
100+
expectTypeOf(t('new.key', { defaultValue: 'some default value' })).toMatchTypeOf<string>();
101+
expectTypeOf(t('new.key', 'some default value')).toMatchTypeOf<string>();
102102
});
103103
});
104104

test/typescript/custom-types-json-v3/i18nextT.test.ts

+6-7
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,17 @@ describe('i18next.t', () => {
6969
it('should work with default value', () => {
7070
expectTypeOf(
7171
i18next.t('custom:bar', { defaultValue: 'some default value' }),
72-
).toMatchTypeOf<unknown>();
73-
expectTypeOf(i18next.t('custom:bar', 'some default value')).toMatchTypeOf<unknown>();
72+
).toMatchTypeOf<string>();
73+
expectTypeOf(i18next.t('custom:bar', 'some default value')).toMatchTypeOf<string>();
7474
expectTypeOf(
7575
i18next.t('bar', { ns: 'custom', defaultValue: 'some default value' }),
76-
).toMatchTypeOf<unknown>();
77-
expectTypeOf(i18next.t('bar', { defaultValue: 'some default value' })).toMatchTypeOf<unknown>();
78-
expectTypeOf(i18next.t('bar', 'some default value')).toMatchTypeOf<unknown>();
76+
).toMatchTypeOf<string>();
77+
expectTypeOf(i18next.t('bar', { defaultValue: 'some default value' })).toMatchTypeOf<string>();
78+
expectTypeOf(i18next.t('bar', 'some default value')).toMatchTypeOf<string>();
7979
});
8080

8181
it('should accept any key if default value is provided', () => {
82-
const str: string = i18next.t('unknown-ns:unknown-key', 'default value');
83-
assertType<string>(str);
82+
assertType<'default value'>(i18next.t('unknown-ns:unknown-key', 'default value'));
8483
});
8584

8685
it('should work with plurals', () => {

test/typescript/custom-types-json-v3/t.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ describe('t', () => {
8888
expectTypeOf(
8989
t('foobar.barfoo', { defaultValue: 'some default value' }),
9090
).toMatchTypeOf<unknown>();
91-
expectTypeOf(t('new.key', { defaultValue: 'some default value' })).toEqualTypeOf<unknown>();
92-
expectTypeOf(t('new.key', 'some default value')).toEqualTypeOf<unknown>();
91+
expectTypeOf(t('new.key', { defaultValue: 'some default value' })).toMatchTypeOf<string>();
92+
expectTypeOf(t('new.key', 'some default value')).toMatchTypeOf<string>();
9393
});
9494
});
9595

test/typescript/custom-types/i18nextT.test.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ describe('i18next.t', () => {
7070
});
7171

7272
it('should accept any key if default value is provided', () => {
73-
const str: string = i18next.t('unknown-ns:unknown-key', 'default value');
74-
assertType<string>(str);
73+
assertType<'default value'>(i18next.t('unknown-ns:unknown-key', 'default value'));
7574
});
7675

7776
it('should fallback for null translations with unset returnNull in config', () => {

test/typescript/custom-types/t.test.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,12 @@ describe('t', () => {
8484
assertType<string[]>(result);
8585
});
8686

87-
it('should not throw an error when `defaultValue` is provided', () => {
87+
it('should not throw an error when `defaultValue` is provided and value should be equal to DefaultValue', () => {
8888
expectTypeOf(
8989
t('foobar.barfoo', { defaultValue: 'some default value' }),
90-
).toMatchTypeOf<unknown>();
91-
expectTypeOf(t('new.key', { defaultValue: 'some default value' })).toEqualTypeOf<unknown>();
92-
expectTypeOf(t('new.key', 'some default value')).toEqualTypeOf<unknown>();
90+
).toMatchTypeOf<string>();
91+
expectTypeOf(t('new.key', { defaultValue: 'some default value' })).toMatchTypeOf<string>();
92+
expectTypeOf(t('new.key', 'some default value')).toMatchTypeOf<string>();
9393
});
9494
});
9595

test/typescript/misc/t.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,12 @@ describe('t', () => {
188188
});
189189

190190
it('`returnObjects`', () => {
191-
expectTypeOf(t('tree', { returnObjects: true, something: 'gold' })).toEqualTypeOf<
191+
expectTypeOf(t('tree', { returnObjects: true, something: 'gold' })).toMatchTypeOf<
192192
object | Array<string | object>
193193
>();
194194
// -> { res: 'added gold' }
195195

196-
expectTypeOf(t('array', { returnObjects: true })).toEqualTypeOf<
196+
expectTypeOf(t('array', { returnObjects: true })).toMatchTypeOf<
197197
object | Array<string | object>
198198
>();
199199
// -> ['a', 'b', 'c']
@@ -214,7 +214,7 @@ describe('t', () => {
214214
it('`returnObjects` + `returnDetails`', () => {
215215
expectTypeOf(t('test', { returnObjects: true, returnDetails: true }))
216216
.toHaveProperty('res')
217-
.toEqualTypeOf<object | Array<string | object>>();
217+
.toMatchTypeOf<object | Array<string | object>>();
218218
});
219219

220220
it('should provide information when `returnDetails` is `true`', () => {

typescript/helpers.d.ts

+8
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,11 @@ type $StringKeyPathToRecordUnion<
5858
export type $StringKeyPathToRecord<TPath extends string, TValue> = $UnionToIntersection<
5959
$StringKeyPathToRecordUnion<TPath, TValue>
6060
>;
61+
62+
/**
63+
* We could use NoInfer typescript build-in utility,
64+
* however this project still supports ts < 5.4.
65+
*
66+
* @see https://github.com/millsp/ts-toolbelt/blob/master/sources/Function/NoInfer.ts
67+
*/
68+
export type $NoInfer<A> = [A][A extends any ? 0 : never];

typescript/t.d.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
$Dictionary,
55
$SpecialObject,
66
$StringKeyPathToRecord,
7+
$NoInfer,
78
} from './helpers.js';
89
import type {
910
TypeOptions,
@@ -260,6 +261,12 @@ export type TFunctionDetailedResult<T = string, TOpt extends TOptions = {}> = {
260261
usedParams: InterpolationMap<T> & { count?: TOpt['count'] };
261262
};
262263

264+
type TFunctionProcessReturnValue<Ret, DefaultValue> = Ret extends string | $SpecialObject | null
265+
? Ret
266+
: [DefaultValue] extends [never]
267+
? Ret
268+
: DefaultValue;
269+
263270
type TFunctionReturnOptionalDetails<Ret, TOpt extends TOptions> = TOpt['returnDetails'] extends true
264271
? TFunctionDetailedResult<Ret, TOpt>
265272
: Ret;
@@ -278,12 +285,13 @@ export interface TFunction<Ns extends Namespace = DefaultNamespace, KPrefix = un
278285
const TOpt extends TOptions,
279286
Ret extends TFunctionReturn<Ns, AppendKeyPrefix<Key, KPrefix>, TOpt>,
280287
const ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>,
288+
DefaultValue extends string = never,
281289
>(
282290
...args:
283291
| [key: Key | Key[], options?: ActualOptions]
284-
| [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }]
285-
| [key: string | string[], defaultValue: string, options?: TOpt & $Dictionary]
286-
): TFunctionReturnOptionalDetails<Ret, TOpt>;
292+
| [key: string | string[], options: TOpt & $Dictionary & { defaultValue: DefaultValue }]
293+
| [key: string | string[], defaultValue: DefaultValue, options?: TOpt & $Dictionary]
294+
): TFunctionReturnOptionalDetails<TFunctionProcessReturnValue<$NoInfer<Ret>, DefaultValue>, TOpt>;
287295
}
288296

289297
export type KeyPrefix<Ns extends Namespace> = ResourceKeys<true>[$FirstNamespace<Ns>] | undefined;

0 commit comments

Comments
 (0)