Skip to content

Commit 72fa9d0

Browse files
committed
feat(no-base-to-string): add checkUnknown option (#533)
refs oxc-project/oxc#16978 typescript-eslint/typescript-eslint#11128
1 parent 28cdb4b commit 72fa9d0

4 files changed

Lines changed: 121 additions & 10 deletions

File tree

internal/rules/no_base_to_string/no_base_to_string.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ var NoBaseToStringRule = rule.Rule{
194194
return collectToStringCertainty(constraint, visited)
195195
}
196196
// unconstrained generic means `unknown`
197+
if opts.CheckUnknown {
198+
return usefulnessSometimes
199+
}
197200
return usefulnessAlways
198201
}
199202

@@ -231,7 +234,11 @@ var NoBaseToStringRule = rule.Rule{
231234
toString = checker.Checker_getPropertyOfType(ctx.TypeChecker, t, "toLocaleString")
232235
}
233236
if toString == nil {
234-
// e.g. any/unknown
237+
// unknown
238+
if opts.CheckUnknown && utils.IsTypeFlagSet(t, checker.TypeFlagsUnknown) {
239+
return usefulnessSometimes
240+
}
241+
// e.g. any
235242
return usefulnessAlways
236243
}
237244

internal/rules/no_base_to_string/no_base_to_string_test.go

Lines changed: 102 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -487,15 +487,6 @@ declare const bb: ExtendedGuildChannel;
487487
bb.toString();
488488
`},
489489
{Code: `
490-
function foo<T>(x: T) {
491-
String(x);
492-
}
493-
`},
494-
{Code: `
495-
declare const u: unknown;
496-
String(u);
497-
`},
498-
{Code: `
499490
type Value = string | Value[];
500491
declare const v: Value;
501492
@@ -523,7 +514,109 @@ String(v);
523514
declare const v: ('foo' | 'bar')[][];
524515
String(v);
525516
`},
517+
// unknown type - valid by default (checkUnknown: false)
518+
{Code: "declare const x: unknown;\n`${x})`;\n"},
519+
{Code: "declare const x: unknown;\nx.toString();\n"},
520+
{Code: "declare const x: unknown;\nx.toLocaleString();\n"},
521+
{Code: "declare const x: unknown;\n'' + x;\n"},
522+
{Code: "declare const x: unknown;\nString(x);\n"},
523+
{Code: "declare const x: unknown;\n'' += x;\n"},
524+
// unconstrained generic - valid by default (checkUnknown: false)
525+
{Code: "function foo<T>(x: T) {\n String(x);\n}\n"},
526+
// any type - always valid
527+
{Code: "declare const x: any;\n`${x})`;\n"},
528+
{Code: "declare const x: any;\nx.toString();\n"},
529+
{Code: "declare const x: any;\nx.toLocaleString();\n"},
530+
{Code: "declare const x: any;\n'' + x;\n"},
531+
{Code: "declare const x: any;\nString(x);\n"},
532+
{Code: "declare const x: any;\n'' += x;\n"},
526533
}), []rule_tester.InvalidTestCase{
534+
// Tests with checkUnknown: true
535+
{
536+
Code: `
537+
declare const x: unknown;
538+
` + "`" + `${x})` + "`" + `;
539+
`,
540+
Options: NoBaseToStringOptions{CheckUnknown: true},
541+
Errors: []rule_tester.InvalidTestCaseError{
542+
{
543+
MessageId: "baseToString",
544+
},
545+
},
546+
},
547+
{
548+
Code: `
549+
declare const x: unknown;
550+
x.toString();
551+
`,
552+
Options: NoBaseToStringOptions{CheckUnknown: true},
553+
Errors: []rule_tester.InvalidTestCaseError{
554+
{
555+
MessageId: "baseToString",
556+
},
557+
},
558+
},
559+
{
560+
Code: `
561+
declare const x: unknown;
562+
x.toLocaleString();
563+
`,
564+
Options: NoBaseToStringOptions{CheckUnknown: true},
565+
Errors: []rule_tester.InvalidTestCaseError{
566+
{
567+
MessageId: "baseToString",
568+
},
569+
},
570+
},
571+
{
572+
Code: `
573+
declare const x: unknown;
574+
'' + x;
575+
`,
576+
Options: NoBaseToStringOptions{CheckUnknown: true},
577+
Errors: []rule_tester.InvalidTestCaseError{
578+
{
579+
MessageId: "baseToString",
580+
},
581+
},
582+
},
583+
{
584+
Code: `
585+
declare const x: unknown;
586+
String(x);
587+
`,
588+
Options: NoBaseToStringOptions{CheckUnknown: true},
589+
Errors: []rule_tester.InvalidTestCaseError{
590+
{
591+
MessageId: "baseToString",
592+
},
593+
},
594+
},
595+
{
596+
Code: `
597+
declare const x: unknown;
598+
'' += x;
599+
`,
600+
Options: NoBaseToStringOptions{CheckUnknown: true},
601+
Errors: []rule_tester.InvalidTestCaseError{
602+
{
603+
MessageId: "baseToString",
604+
},
605+
},
606+
},
607+
{
608+
Code: `
609+
function foo<T>(x: T) {
610+
String(x);
611+
}
612+
`,
613+
Options: NoBaseToStringOptions{CheckUnknown: true},
614+
Errors: []rule_tester.InvalidTestCaseError{
615+
{
616+
MessageId: "baseToString",
617+
},
618+
},
619+
},
527620
{
528621
Code: "`${{}})`;",
529622
Errors: []rule_tester.InvalidTestCaseError{

internal/rules/no_base_to_string/options.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/rules/no_base_to_string/schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
"no_base_to_string_options": {
55
"type": "object",
66
"properties": {
7+
"checkUnknown": {
8+
"type": "boolean",
9+
"description": "Whether to also check values of type `unknown`.",
10+
"default": false
11+
},
712
"ignoredTypeNames": {
813
"type": "array",
914
"items": {

0 commit comments

Comments
 (0)