Skip to content

Commit 77641b0

Browse files
committed
Document as const recommendation
Closes #83
1 parent 9c5e1af commit 77641b0

File tree

4 files changed

+102
-4
lines changed

4 files changed

+102
-4
lines changed

index.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ export type Options = {
9494
/**
9595
Exclude keys from being camel-cased.
9696
97-
If this option can be statically determined, it's recommended to add `as const` to it.
98-
9997
@default []
98+
99+
For correct TypeScript types when using this option with a string array, add `as const` to the array.
100100
*/
101101
readonly exclude?: ReadonlyArray<string | RegExp>;
102102

@@ -164,10 +164,10 @@ export type Options = {
164164
/**
165165
Exclude children at the given object paths in dot-notation from being camel-cased. For example, with an object like `{a: {b: '🦄'}}`, the object path to reach the unicorn is `'a.b'`.
166166
167-
If this option can be statically determined, it's recommended to add `as const` to it.
168-
169167
@default []
170168
169+
For correct TypeScript types when using this option, add `as const` to the array.
170+
171171
@example
172172
```
173173
import camelcaseKeys from 'camelcase-keys';

index.test-d.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,3 +442,92 @@ expectType<Array<{'4.2': string}>>(camelcaseKeys([{'4.2': 'foo'}]));
442442

443443
// Non-numeric keys starting with numbers should still be transformed
444444
expectType<{'42Foo': string}>(camelcaseKeys({'42-foo': 'value'}));
445+
446+
// Test for issue #83 - exclude without `as const`
447+
type Language = {
448+
iso_639_1: string;
449+
name: string;
450+
};
451+
452+
type Image = {
453+
aspect_ratio: number;
454+
file_path: string;
455+
height: number;
456+
iso_639_1: string | undefined;
457+
vote_average: number;
458+
vote_count: number;
459+
width: number;
460+
};
461+
462+
type MovieDetails = {
463+
id: number;
464+
spoken_languages: Language[];
465+
images: Image[];
466+
};
467+
468+
const movieData: MovieDetails = {
469+
id: 1,
470+
spoken_languages: [
471+
{iso_639_1: 'en', name: 'English'},
472+
],
473+
images: [
474+
{
475+
aspect_ratio: 1.5,
476+
file_path: '/path.jpg',
477+
height: 100,
478+
iso_639_1: 'en',
479+
vote_average: 5,
480+
vote_count: 10,
481+
width: 150,
482+
},
483+
],
484+
};
485+
486+
// WITHOUT `as const` - the problematic case
487+
const result1 = camelcaseKeys(movieData, {
488+
exclude: ['iso_639_1', 'iso_3166_1'],
489+
deep: true,
490+
});
491+
492+
// Since exclude is string[], TypeScript can't properly exclude specific keys
493+
// It will convert everything to camelCase
494+
expectType<{
495+
id: number;
496+
spokenLanguages: Array<{
497+
iso6391: string; // Bug: should be iso_639_1 but TypeScript doesn't know
498+
name: string;
499+
}>;
500+
images: Array<{
501+
aspectRatio: number;
502+
filePath: string;
503+
height: number;
504+
iso6391: string | undefined; // Bug: should be iso_639_1 but TypeScript doesn't know
505+
voteAverage: number;
506+
voteCount: number;
507+
width: number;
508+
}>;
509+
}>(result1);
510+
511+
// WITH `as const` - this works correctly
512+
const result2 = camelcaseKeys(movieData, {
513+
exclude: ['iso_639_1', 'iso_3166_1'] as const,
514+
deep: true,
515+
});
516+
517+
// With as const, TypeScript knows the exact strings in the exclude array
518+
expectType<{
519+
id: number;
520+
spokenLanguages: Array<{
521+
iso_639_1: string; // Correctly preserved
522+
name: string;
523+
}>;
524+
images: Array<{
525+
aspectRatio: number;
526+
filePath: string;
527+
height: number;
528+
iso_639_1: string | undefined; // Correctly preserved
529+
voteAverage: number;
530+
voteCount: number;
531+
width: number;
532+
}>;
533+
}>(result2);

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,10 @@
6464
"matcha": "^0.7.0",
6565
"tsd": "^0.33.0",
6666
"xo": "^1.2.2"
67+
},
68+
"xo": {
69+
"rules": {
70+
"@typescript-eslint/unified-signatures": "off"
71+
}
6772
}
6873
}

readme.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ Default: `[]`
5454

5555
Exclude keys from being camel-cased.
5656

57+
For correct TypeScript types when using this option with a string array, add `as const` to the array.
58+
5759
##### deep
5860

5961
Type: `boolean`\
@@ -119,6 +121,8 @@ Default: `[]`
119121
120122
Exclude children at the given object paths in dot-notation from being camel-cased.
121123
124+
For correct TypeScript types when using this option, add `as const` to the array.
125+
122126
For example, with an object like `{a: {b: '🦄'}}`, the object path to reach the unicorn is `'a.b'`.
123127

124128
```js

0 commit comments

Comments
 (0)