Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion sdk/core/core-tracing/review/core-tracing.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

```ts

// @public
export type AwaitedLike<T> = T extends object & {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AwaitedLike is somewhat strange as a name since it makes it sound like an interface for something that is "like an Awaited instance." Maybe something like UnwrapThenable if you really don't want to overlap with TS4.5's Awaited name.

Since tracing is in beta we can remove this in the future if we decide that we can rely on TS4.5's definition.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, since { then: ... } is a subtype of object, there shouldn't be any difference between object & { then: ... } and { then: ... }.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, since { then: ... } is a subtype of object, there shouldn't be any difference between object & { then: ... } and { then: ... }.

Thanks, yeah good call!

As far as the name... maybe AwaitedThenable? I like having Awaited in the name what do you think?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was chatting with Jeff and we went with Resolved<T> which feels appropriate here where the returntype is:

Promise<Resolved<ReturnType<Callback>>>;

then(onfulfilled: infer F): any;
} ? F extends (value: infer V) => any ? AwaitedLike<V> : never : T;

// @public
export function createTracingClient(options: TracingClientOptions): TracingClient;

Expand Down Expand Up @@ -57,7 +62,7 @@ export interface TracingClient {
withContext<CallbackArgs extends unknown[], Callback extends (...args: CallbackArgs) => ReturnType<Callback>>(context: TracingContext, callback: Callback, ...callbackArgs: CallbackArgs): ReturnType<Callback>;
withSpan<Options extends {
tracingOptions?: OperationTracingOptions;
}, Callback extends (updatedOptions: Options, span: Omit<TracingSpan, "end">) => ReturnType<Callback>>(name: string, operationOptions: Options, callback: Callback, spanOptions?: TracingSpanOptions): Promise<ReturnType<Callback>>;
}, Callback extends (updatedOptions: Options, span: Omit<TracingSpan, "end">) => ReturnType<Callback>>(name: string, operationOptions: Options, callback: Callback, spanOptions?: TracingSpanOptions): Promise<AwaitedLike<ReturnType<Callback>>>;
}

// @public
Expand Down
1 change: 1 addition & 0 deletions sdk/core/core-tracing/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT license.

export {
AwaitedLike,
Instrumenter,
InstrumenterSpanOptions,
OperationTracingOptions,
Expand Down
15 changes: 14 additions & 1 deletion sdk/core/core-tracing/src/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

/**
* A narrower version of TypeScript 4.5's Awaited type which Recursively
* unwraps the "awaited type", emulating the behavior of `await`.
*/
// eslint-disable-next-line @typescript-eslint/ban-types -- I want to stay consistent with TypeScript 4.5's Awaited type
export type AwaitedLike<T> = T extends object & { then(onfulfilled: infer F): any } // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These comments are great! Thanks for documenting this type 😄

? F extends (value: infer V) => any // if the argument to `then` is callable, extracts the first argument
? AwaitedLike<V> // recursively unwrap the value
: never // the argument to `then` was not callable
: T; // non-object or non-thenable

/**
* Represents a client that can integrate with the currently configured {@link Instrumenter}.
*
Expand All @@ -12,6 +23,8 @@ export interface TracingClient {
*
* This is the primary interface for using Tracing and will handle error recording as well as setting the status on the span.
*
* Both synchronous and asynchronous functions will be awaited in order to reflect the result of the callback on the span.
*
* Example:
*
* ```ts
Expand All @@ -32,7 +45,7 @@ export interface TracingClient {
operationOptions: Options,
callback: Callback,
spanOptions?: TracingSpanOptions
): Promise<ReturnType<Callback>>;
): Promise<AwaitedLike<ReturnType<Callback>>>;
/**
* Starts a given span but does not set it as the active span.
*
Expand Down
5 changes: 3 additions & 2 deletions sdk/core/core-tracing/src/tracingClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT license.

import {
AwaitedLike,
OperationTracingOptions,
TracingClient,
TracingClientOptions,
Expand Down Expand Up @@ -64,14 +65,14 @@ export function createTracingClient(options: TracingClientOptions): TracingClien
operationOptions: Options,
callback: Callback,
spanOptions?: TracingSpanOptions
): Promise<ReturnType<Callback>> {
): Promise<AwaitedLike<ReturnType<Callback>>> {
const { span, updatedOptions } = startSpan(name, operationOptions, spanOptions);
try {
const result = await withContext(updatedOptions.tracingOptions!.tracingContext!, () =>
Promise.resolve(callback(updatedOptions, span))
);
span.setStatus({ status: "success" });
return result;
return result as ReturnType<typeof withSpan>;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed in TS 4.4 see playground link but for reasons unknown to me TS4.2 infers the returntype of this as unknown

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for sharing the playground!

} catch (err) {
span.setStatus({ status: "error", error: err });
throw err;
Expand Down