Here is a version that works with both readonly and mutable tuples types and a separator.
type Join<
TElements,
TSeparator extends string,
> = TElements extends Readonly<[infer First, ...infer Rest]>
? Rest extends ReadonlyArray<string>
? First extends string
? `${First}${Rest extends [] ? '' : TSeparator}${Join<Rest, TSeparator>}`
: never
: never
: '';
type MutableTuple = ["a", "b", "c"];
type MutableTupleJoined = Join<MutableTuple, " | ">;
// ^? "a | b | c"
type ReadonlyTuple = readonly ["a", "b", "c"];
type ReadonlyTupleJoined = Join<ReadonlyTuple, " | ">;
// ^? "a | b | c"
A readonly type often comes from const assertions e.g.
const tuple = ["a", "b", "c"] as const;
type Joined = Join<typeof tuple, " | ">;
When inlining the tuple type, it is usually mutable e.g.
type Joined = Join<["a", "b", "c"], " | ">;
Answer from nyarthan on Stack OverflowArray.join has improper typing in .d.ts file
JavaScript/TypeScript: Concatenate string variables and string arrays with accordingly set spaces - Stack Overflow
How to `join` an Array of String with a prefix for each string?
Having trouble concatenating two strings in TypeScript
Here is a version that works with both readonly and mutable tuples types and a separator.
type Join<
TElements,
TSeparator extends string,
> = TElements extends Readonly<[infer First, ...infer Rest]>
? Rest extends ReadonlyArray<string>
? First extends string
? `${First}${Rest extends [] ? '' : TSeparator}${Join<Rest, TSeparator>}`
: never
: never
: '';
type MutableTuple = ["a", "b", "c"];
type MutableTupleJoined = Join<MutableTuple, " | ">;
// ^? "a | b | c"
type ReadonlyTuple = readonly ["a", "b", "c"];
type ReadonlyTupleJoined = Join<ReadonlyTuple, " | ">;
// ^? "a | b | c"
A readonly type often comes from const assertions e.g.
const tuple = ["a", "b", "c"] as const;
type Joined = Join<typeof tuple, " | ">;
When inlining the tuple type, it is usually mutable e.g.
type Joined = Join<["a", "b", "c"], " | ">;
const arr = ['a', 'b'] as const;
type JoinStrings<T extends readonly string[]> = T extends readonly [infer F, ...infer R]
? `${F}${JoinStrings<R>}`
: '';
const joinArray = <T extends readonly string[]>(arr: T): JoinStrings<T> => arr.join('') as JoinStrings<T>;
const joined = joinArray(arr);
You can use destructuring to concatenate everything into a temporary array, and then use filter to remove any empty elements before calling join on the lot.
let var1 = "var1";
let arr1 = ["one", "", "two"];
let var2 = ""
const myString = "result:" + [var1, ...arr1, var2].filter(s => s).join(' ');
console.log(myString);
Does this satisfy your requirements?
const strArr = ['result:' + var1, ...arr1, var2].map((a) => a.trim()).join(' ')
Update
As suggested, following handles
- empty string
- string with multiple spaces
- trim additional spaces
const strArr = ['result:' + var1, ...arr1, var2].map((a) => a.trim()).filter(Boolean).join(' ')
Update 2
If you are using ES2019, you could do this in single pass:
const strArr =
['result:' + var1, ...arr1, var2]
.flatMap((el) => Boolean(el.trim()) ? [el.trim()] :[]).join(' ')
» npm install join-string
I think a more ergonomic (if not idiomatic) approach would be using template literals, for example:
Code in TypeScript Playground
const example = {
IdNumber: 524242,
notes: 'testing\n\ntesting 2\n\ntesting 3',
update () {
this.notes = `IdNumber: ${this.IdNumber}\n\n${this.notes}`;
},
};
console.log(example.notes); // "testing\n\ntesting 2\n\ntesting 3"
example.update();
console.log(example.notes); // "IdNumber: 524242\n\ntesting\n\ntesting 2\n\ntesting 3"
For string concatenation it is recommended* to use Template Literals
let string1 = `IdNumber: ${this.IdNumber}`;
let string2 = `${this.notes}`;
this.notes = `${string1}${string2}`
* https://eslint.org/docs/latest/rules/prefer-template