get rid of Symbol iterator in autocomplete

Hi TS nerds, I'm in dire need of help; For a bit of context, I have a function that returns a tuple: const [hej, do] = myFunc(), and I'm looking to allow an object being returned by the same function: const obj = myFunc() // obj.hej and obj.do exist. for WAY more accurate code, see: https://github.com/bdsqqq/try/pull/10 My solution of choice rn would be:
export const trytm = async <T>(
promise: Promise<T>,
): Promise<TryResult<T>> => {
const getResult = (data: T | null, error: Error | null) => ({
data,
error,
[Symbol.iterator]: function* () {
yield this.data;
yield this.error;
}
})
try {
const data = await promise;
return getResult(data, null);
} catch (throwable) {
if (throwable instanceof Error) {
return getResult(null, throwable);
}

throw throwable;
}
};
export const trytm = async <T>(
promise: Promise<T>,
): Promise<TryResult<T>> => {
const getResult = (data: T | null, error: Error | null) => ({
data,
error,
[Symbol.iterator]: function* () {
yield this.data;
yield this.error;
}
})
try {
const data = await promise;
return getResult(data, null);
} catch (throwable) {
if (throwable instanceof Error) {
return getResult(null, throwable);
}

throw throwable;
}
};
But this makes the autocomplete of the object include data, error AND Symbol... Is there any way to not have Symbol there??
1 Reply
bedesqui
bedesqui16mo ago
A proposed solution was:
class TryResult<T extends any | null> {
private [Symbol.iterator] = function* (): IterableIterator<[T | null, Error | null]> {
yield [this.data, this.error];
}
public data: T | null;
public error: Error | null;

constructor(data: T, error: Error | null) {
this.data = data;
this.error = error;
}
}

export const trytm = async <T>(
promise: Promise<T>,
): Promise<TryResult<T | null>> => {

try {
const data = await promise;
return new TryResult(data, null);
} catch (throwable) {
if (throwable instanceof Error) {
return new TryResult(null, throwable);
}
throw throwable;
}
};

const mockPromise = new Promise<string>((resolve) => {
setTimeout(() => {
resolve('hello');
}, 1000);
})

async function main() {
const [[data, error]] = await trytm(mockPromise);
const result = await trytm(mockPromise);
}
class TryResult<T extends any | null> {
private [Symbol.iterator] = function* (): IterableIterator<[T | null, Error | null]> {
yield [this.data, this.error];
}
public data: T | null;
public error: Error | null;

constructor(data: T, error: Error | null) {
this.data = data;
this.error = error;
}
}

export const trytm = async <T>(
promise: Promise<T>,
): Promise<TryResult<T | null>> => {

try {
const data = await promise;
return new TryResult(data, null);
} catch (throwable) {
if (throwable instanceof Error) {
return new TryResult(null, throwable);
}
throw throwable;
}
};

const mockPromise = new Promise<string>((resolve) => {
setTimeout(() => {
resolve('hello');
}, 1000);
})

async function main() {
const [[data, error]] = await trytm(mockPromise);
const result = await trytm(mockPromise);
}
But this makes the destructures look like like [[data, error]] Fineeeeeeee, the symbol iterator is supposed to be there, removing it would be lying to the user