Skip to content

Conversation

@Groupguanfang
Copy link
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings January 29, 2026 12:14
@changeset-bot
Copy link

changeset-bot bot commented Jan 29, 2026

🦋 Changeset detected

Latest commit: ceec23d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 15 packages
Name Type
@unioc/core Patch
@unioc/web-bun Patch
@unioc/web-express Patch
@unioc/web-koa Patch
@unioc/web Patch
@unioc/commander Patch
@unioc/adapter-midway Patch
@unioc/adapter-nestjs Patch
@unioc/vscode Patch
@unioc/signals Patch
unioc Patch
create-unioc Patch
fixture-midway Patch
fixture-bun Patch
fixture-koa Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 29, 2026

Open in StackBlitz

unioc

npm i https://pkg.pr.new/iocjs/unioc@208

@unioc/adapter-midway

npm i https://pkg.pr.new/iocjs/unioc/@unioc/adapter-midway@208

@unioc/adapter-nestjs

npm i https://pkg.pr.new/iocjs/unioc/@unioc/adapter-nestjs@208

@unioc/commander

npm i https://pkg.pr.new/iocjs/unioc/@unioc/commander@208

create-unioc

npm i https://pkg.pr.new/iocjs/unioc/create-unioc@208

@unioc/core

npm i https://pkg.pr.new/iocjs/unioc/@unioc/core@208

@unioc/decorator

npm i https://pkg.pr.new/iocjs/unioc/@unioc/decorator@208

@unioc/meta

npm i https://pkg.pr.new/iocjs/unioc/@unioc/meta@208

@unioc/reflector

npm i https://pkg.pr.new/iocjs/unioc/@unioc/reflector@208

@unioc/shared

npm i https://pkg.pr.new/iocjs/unioc/@unioc/shared@208

@unioc/web

npm i https://pkg.pr.new/iocjs/unioc/@unioc/web@208

@unioc/web-bun

npm i https://pkg.pr.new/iocjs/unioc/@unioc/web-bun@208

@unioc/web-express

npm i https://pkg.pr.new/iocjs/unioc/@unioc/web-express@208

@unioc/web-koa

npm i https://pkg.pr.new/iocjs/unioc/@unioc/web-koa@208

commit: ceec23d

@Groupguanfang Groupguanfang merged commit dc4fbff into v1 Jan 29, 2026
13 checks passed
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a bug in property design type resolution by adding proper validation and fallback logic when resolving dependencies for properties decorated with @Inject.

Changes:

  • Adds validation to check if design type exists in container before attempting to create a new instance
  • Adds isClass validation to ensure design type is actually a class before attempting instantiation
  • Implements proper error handling for non-optional properties with invalid design types
  • Handles optional properties gracefully by setting them to undefined when design type is invalid

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
packages/core/core/src/contexts/classes/class-factory.ts Refactors _resolveInjected method to add multi-step validation and resolution logic for property design types, including container lookup, class validation, and optional property handling
.changeset/floppy-towns-invent.md Adds changeset entry documenting the fix (contains a minor spelling error)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const currentDesignType = this.getClassWrapper()
.getMetadataScanner()
.getPropertyDesignType(item.propertyKey)
.getPropertyDesignType(item.propertyKey) as unknown
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The type assertion as unknown appears unnecessary here. The getPropertyDesignType method already returns IClass | undefined according to the interface definition. This type assertion weakens type safety without providing clear benefits. Consider removing it or explaining why it's needed.

Copilot uses AI. Check for mistakes.
}
}
else {
throw new Error(`Property ${item.propertyKey.toString()} is decorated with @Inject, but the property is not a class property.`)
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The error message format is inconsistent with other errors in this method. Lines 84 and 100 use the format Property "{ClassName}.{propertyKey}", but this line uses Property {propertyKey} without the class name prefix. For consistency and better debugging, this should match the pattern used in the other error messages.

Suggested change
throw new Error(`Property ${item.propertyKey.toString()} is decorated with @Inject, but the property is not a class property.`)
throw new Error(`Property "${this.getClassWrapper().getTarget().name}.${item.propertyKey.toString()}" is decorated with @Inject, but the property is not a class property.`)

Copilot uses AI. Check for mistakes.
"@unioc/core": patch
---

fix: resolve properties's design type
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

Incorrect possessive form. "properties's" should be "property's" (if referring to a single property) or "properties'" (if referring to multiple properties). Based on the context of the PR fixing property design type resolution, "property's" is likely the correct form.

Suggested change
fix: resolve properties's design type
fix: resolve property's design type

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +104
continue
}
else if (isClass(currentDesignType)) {
const classWrapper = this.getClassWrapper().getBootstrap().createClass(currentDesignType)
instance[item.propertyKey] = await classWrapper.resolve()
continue
}
else if (item.optional === false) {
throw new Error(`Property "${this.getClassWrapper().getTarget().name}.${item.propertyKey.toString()}" is decorated with @Inject, but the design type "${currentDesignType.toString()}" is not found.`)
}
else {
instance[item.propertyKey] = undefined
continue
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The continue statements on lines 92, 97, and 104 are unnecessary because they are at the end of their respective conditional blocks within the loop. Removing them would make the code cleaner without changing behavior, as the loop naturally continues to the next iteration after completing each block.

Suggested change
continue
}
else if (isClass(currentDesignType)) {
const classWrapper = this.getClassWrapper().getBootstrap().createClass(currentDesignType)
instance[item.propertyKey] = await classWrapper.resolve()
continue
}
else if (item.optional === false) {
throw new Error(`Property "${this.getClassWrapper().getTarget().name}.${item.propertyKey.toString()}" is decorated with @Inject, but the design type "${currentDesignType.toString()}" is not found.`)
}
else {
instance[item.propertyKey] = undefined
continue
}
else if (isClass(currentDesignType)) {
const classWrapper = this.getClassWrapper().getBootstrap().createClass(currentDesignType)
instance[item.propertyKey] = await classWrapper.resolve()
}
else if (item.optional === false) {
throw new Error(`Property "${this.getClassWrapper().getTarget().name}.${item.propertyKey.toString()}" is decorated with @Inject, but the design type "${currentDesignType.toString()}" is not found.`)
}
else {
instance[item.propertyKey] = undefined

Copilot uses AI. Check for mistakes.
Comment on lines +89 to +105
const foundWrapper = GLOBAL_CONTAINER.findOne(currentDesignType as IContainer.InjectionToken)
if (foundWrapper) {
instance[item.propertyKey] = await foundWrapper.resolve()
continue
}
else if (isClass(currentDesignType)) {
const classWrapper = this.getClassWrapper().getBootstrap().createClass(currentDesignType)
instance[item.propertyKey] = await classWrapper.resolve()
continue
}
else if (item.optional === false) {
throw new Error(`Property "${this.getClassWrapper().getTarget().name}.${item.propertyKey.toString()}" is decorated with @Inject, but the design type "${currentDesignType.toString()}" is not found.`)
}
else {
instance[item.propertyKey] = undefined
continue
}
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The new logic branches introduced in this PR lack test coverage. The existing test only covers the case where an explicit injection token is provided (line 24 of index.test.ts). Consider adding tests for: 1) design type found in container, 2) design type that is a class but not registered in container, 3) optional properties with non-class design types, and 4) non-optional properties with invalid design types to verify error handling.

Copilot uses AI. Check for mistakes.
continue
}
else if (item.optional === false) {
throw new Error(`Property "${this.getClassWrapper().getTarget().name}.${item.propertyKey.toString()}" is decorated with @Inject, but the design type "${currentDesignType.toString()}" is not found.`)
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

Calling .toString() on currentDesignType in the error message may not produce meaningful output for all cases. When TypeScript's reflection metadata returns primitive constructors (String, Number, Boolean) or Object for complex types, .toString() will show function String() { [native code] } or similar. Consider using typeof currentDesignType === 'function' ? currentDesignType.name : String(currentDesignType) to make the error message more readable.

Suggested change
throw new Error(`Property "${this.getClassWrapper().getTarget().name}.${item.propertyKey.toString()}" is decorated with @Inject, but the design type "${currentDesignType.toString()}" is not found.`)
throw new Error(`Property "${this.getClassWrapper().getTarget().name}.${item.propertyKey.toString()}" is decorated with @Inject, but the design type "${typeof currentDesignType === 'function' ? currentDesignType.name : String(currentDesignType)}" is not found.`)

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants